如果 Python,为什么-1
两者-2
都哈希到相同的数字?
既然他们这样做了,Python 是如何区分这两个数字的呢?
>>> -1 is -2
False
>>> hash(-1) is hash(-2)
True
>>> hash(-1)
-2
>>> hash(-2)
-2
如果 Python,为什么-1
两者-2
都哈希到相同的数字?
既然他们这样做了,Python 是如何区分这两个数字的呢?
>>> -1 is -2
False
>>> hash(-1) is hash(-2)
True
>>> hash(-1)
-2
>>> hash(-2)
-2
-1
是 CPython 的 C 级别的保留值,它防止哈希函数能够产生-1
. 正如 DSM 所指出的,IronPython 和 PyPy 中的情况并非如此hash(-1) != hash(-2)
。
请参阅此 Quora 答案:
如果你在 C 扩展模块中编写一个类型并提供一个
tp_hash
方法,你必须避免-1
——如果你 return-1
,Python 会假设你打算抛出一个错误。如果你用纯 Python 编写一个类并提供一个
__hash__
方法,那么谢天谢地,没有这样的要求。但那是因为调用您的__hash__
方法的 C 代码会为您执行此操作 - 如果您的__hash__
返回-1
,则hash()
应用于您的对象将实际返回-2
。
这实际上只是重新包装了来自effbot的信息:
哈希值
-1
是保留的(它用于标记 C 实现中的错误)。如果哈希算法生成这个值,我们就简单地使用-2
。
您也可以在源代码中看到这一点。例如对于 Python 3 的int
对象,这是在哈希实现的末尾:
if (x == (Py_uhash_t)-1)
x = (Py_uhash_t)-2;
return (Py_hash_t)x;
既然他们这样做了,Python 是如何区分这两个数字的呢?
由于所有散列函数都将较大的输入空间映射到较小的输入空间,因此无论散列函数有多好,总是会发生冲突。例如,考虑散列字符串。如果哈希码是 32 位整数,则您有 2^32(略多于 40 亿)个哈希码。如果您考虑所有长度为 6 的 ASCII 字符串,您的输入空间中有 (2^7)^6(略低于 4.4 万亿)不同的项目。仅此一套,无论您多么出色,都可以保证有很多很多碰撞。向其中添加 Unicode 字符和无限长度的字符串!
因此,哈希码仅提示对象的位置,随后进行相等性测试以测试候选键。要在哈希表集中实现成员资格测试,哈希码会为您提供“桶”编号,以便在其中搜索值。但是,所有具有相同哈希码的集合项都在存储桶中。为此,您还需要一个相等性测试来区分存储桶中的所有候选者。
这种散列码和相等对偶性在CPython 的可散列对象文档中有所暗示。在其他语言/框架中,有一个准则/规则,如果您提供自定义哈希码函数,您还必须提供自定义相等测试(在与哈希码函数相同的字段上执行)。
事实上,今天的 Python 版本正好解决了这个问题,当它(相同的哈希值,但大规模)被用作拒绝服务攻击时,它提供了一个安全补丁来解决效率问题 - http://mail.python.org /pipermail/python-list/2012-April/1290792.html