总结:这不是巧合; _PyHASH_INF is hardcoded as 314159 在 Python 的默认 CPython 实现中,并被选为任意值(显然来自 π 的数字)by Tim Peters in 2000。
hash(float('inf')) 的值是数字类型内置哈希函数的系统相关参数之一,is also available 在 Python 3 中为 sys.hash_info.inf:
>>> import sys
>>> sys.hash_info
sys.hash_info(width=64, modulus=2305843009213693951, inf=314159, nan=0, imag=1000003, algorithm='siphash24', hash_bits=64, seed_bits=128, cutoff=0)
>>> sys.hash_info.inf
314159
(同样的结果with PyPy。)
在代码方面,hash 是一个内置函数。在 Python 浮点对象上调用它会调用其指针由内置浮点类型 (PyTypeObject PyFloat_Type) 的tp_hash attribute 给出的函数,其中is 是float_hash 函数,defined 为return _Py_HashDouble(v->ob_fval),反过来has
if (Py_IS_INFINITY(v))
return v > 0 ? _PyHASH_INF : -_PyHASH_INF;
其中_PyHASH_INF 是defined as 314159:
#define _PyHASH_INF 314159
就历史而言,314159 在 Python 代码(您可以通过 git bisect 或 git log -S 314159 -p 找到)中首次提及 314159 是由 Tim Peters 在 2000 年 8 月添加的,现在是在cpython git 存储库中提交39dce293。
提交信息说:
修复http://sourceforge.net/bugs/?func=detailbug&bug_id=111866&group_id=5470。
这是一个误导性的错误——真正的“错误”是hash(x) 给出了一个错误
当x 是无穷大时返回。解决了这个问题。添加了新的Py_IS_INFINITY 宏到
pyport.h。重新排列代码以减少浮点和散列中不断增长的重复
复数,将特伦特早先的尝试推向了一个合乎逻辑的结论。
修复了极其罕见的错误,即使存在浮点数的散列也可能返回 -1
不是错误(没有浪费时间尝试构建测试用例,它只是
从代码中可以明显看出它可能发生)。改进了复杂的哈希,以便
hash(complex(x, y)) 不再系统地等于 hash(complex(y, x))。
特别是,在这个提交中,他在Objects/floatobject.c 中删除了static long float_hash(PyFloatObject *v) 的代码,并将其改为return _Py_HashDouble(v->ob_fval);,并在Objects/object.c 中long _Py_HashDouble(double v) 的定义中添加了以下几行:
if (Py_IS_INFINITY(intpart))
/* can't convert to long int -- arbitrary */
v = v < 0 ? -271828.0 : 314159.0;
如前所述,这是一个随意的选择。请注意,271828 由e 的前几位小数组成。
相关的后续提交: