在Python/ target=_blank class=infotextkey>Python中,有一个内置函数 hash(),它可以生成任何对象的哈希值,在进行对象不比较的时候,其实就是比较对象的哈希值
但是,你是否做过下面的操纵?
>>> iNFTy = float('inf')
>>> infty
inf
>>> type(infty)
<class 'float'>
>>> hash(infty)
314159
这里创建了一个表示无穷的浮点数对象infty,然后将它作为hash()函数的参数,即得到无穷的哈希值,结果是31459,对这个结果的数字组成,应该并不陌生吧。
>>> import math
>>> int(math.pi*1e5)
314159
它就是组成 的部分数字。为什么会是这个结果,这里有什么玄妙吗?
没有什么玄妙的,都是语言中的规定。不要忘记,Python语言是一种高级编程语言,编程语言都是人工语言,所以就会有很多人为的硬性规定。
回到hash()函数,它是Python的一个内置函数,在上面的程序中调用它的时候,函数的指针由内置float类型(PyTypeObject PyFloat_Type)的tp_hash属性给出,即float_hash函数,并且以return _Py_HashDouble(v-> ob_fval)定义返回值,实现返回值的代码:
if (Py_IS_INFINITY(v))
return v > 0 ? _PyHASH_INF : -_PyHASH_INF;
这里的_PyHASH_INF就定义为314159:
#define _PyHASH_INF 314159
所以,可以把hash(float('inf'))理解为系统的规定,或者,在Python3中,也可以说是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
这个结果,是有其历史原因的。在2000年8月,Tim Peters提交了一个代码,其中修复了当时Python的一个bug。内容如下(
https://Github.com/python/cpython/commit/39dce29365d287dc6b353b2a527dc11fe58dcfa6):
在这次提交的代码中,Tim Peters 将 static long float_hash(PyFloatObject *v 从Objects/floatobject.c中剥离出来,并且实现下面的返回值:return _Py_HashDouble(v->ob_fval);。在Obbjects/obbject.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,就是 自然常数 所包含的几个数字。
但是,如果在Python3中,负无穷的哈希值会是:
>>> hash(float('-inf'))
-314159
在Pyhton2中,结果就不同了:
>>> hash(float('-inf'))
-271828
后来还有一些细微的变化,可以参阅:
https://github.com/python/cpython/commit/985ecdcfc29adfc36ce2339acf03f819ad414869