为什么-1和-2都在Python中哈希到-2?

时间:2012-04-12 19:30:34

标签: python hash cpython

  

可能重复:
  When is a python object's hash computed and why is the hash of -1 different?

为什么-1-2如果是Python,则都会使用相同的数字?

既然他们这样做了,Python如何区分这两个数字?

>>> -1 is -2
False
>>> hash(-1) is hash(-2)
True
>>> hash(-1)
-2
>>> hash(-2)
-2

1 个答案:

答案 0 :(得分:36)

-1是CPython的C级保留值,可防止哈希函数生成哈希值-1。如DSM所述,在IronPython和PyPy hash(-1) != hash(-2)中也是如此。

请参阅this Quora answer

  

如果您在C扩展模块中编写类型并提供tp_hash   方法,你必须避免-1 - 如果你返回-1,Python会假设   你的意思是抛出一个错误。

     

如果您使用纯Python编写类并提供__hash__方法,   谢天谢地,没有这样的要求。但那是因为C代码   调用你的__hash__方法会为你做这件事 - 如果你的话   __hash__返回-1,然后应用于您的对象的hash()实际上会返回-2

这真的只是重新打包来自effbot的信息:

  

保留哈希值-1(它用于标记C中的错误   实现)。如果哈希算法生成此值,我们就简单地说   请改用-2

您也可以在源代码中看到这一点。例如,对于Python 3的int对象,这是the hash implementation的末尾:

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 documentation on hashable objects中暗示了这个哈希码和平等对偶性。在其他语言/框架中,有一条指南/规则,如果您提供自定义哈希代码函数,则还必须提供自定义相等性测试(在与哈希代码函数相同的字段上执行)。


事实上,今天的Python发布正好解决了这个问题,一个安全补丁解决了效率问题,当这个(相同的哈希值,但是大规模)被用作拒绝服务攻击时 - http://mail.python.org/pipermail/python-list/2012-April/1290792.html < / p>