【问题标题】:Why do -1 and -2 both hash to -2 in CPython? [duplicate]为什么 -1 和 -2 在 CPython 中都散列为 -2? [复制]
【发布时间】:2012-04-12 19:30:34
【问题描述】:

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

如果是 Python,为什么 -1-2 都哈希到相同的数字?

既然有,那么 Python 是如何区分这两个数字的呢?

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

【问题讨论】:

  • 这是一个已知问题 - 我认为这里已经存在问题...

标签: python hash cpython


【解决方案1】:

-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

【讨论】:

  • Python 2.7.3 代码链接(用于整数):hg.python.org/cpython/file/70274d53c1dd/Objects/…
  • 您可能想回答第二个问题(Python 如何区分这两个数字)。由于所有散列函数都将较大的输入空间映射到较小的输入空间,因此无论散列函数有多好,都总是会发生冲突。因此,哈希码只提示对象所在的位置,随后进行相等性测试来测试候选键。
  • 只是在某处提到它,hash(-1) != hash(-2) 在 Ironpython 2.6.0.20 和 pypy 1.7.0 中。
  • 当一个问题被关闭时,分数不会消失,只有当它被删除时。
  • 哦,酷。将删除该评论。谢谢。
猜你喜欢
  • 1970-01-01
  • 2011-12-04
  • 1970-01-01
  • 1970-01-01
  • 2012-10-13
  • 2011-10-31
  • 2019-02-18
  • 2011-08-21
  • 1970-01-01
相关资源
最近更新 更多