hash((-2,2)) == hash((2,-2)) 返回 True(Python)

4

所以,这很有趣——Python 的 hash 函数在 hash(-1) == hash(-2) 时返回 True,正如其他讨论中所述,但是这个呢?

>>> hash( (-2,2) ) == hash( (2,-2) )
True

这是一项功能吗?

其他一些快速实验:

>>>(-2,2) == (2,-2)
False
>>>hash( (-1,) ) == hash( (-2,) )
True
>>>hash( (-1,-2) ) == hash( (-2,-1) )
True
>>>hash( (-2.01,2.01) ) == hash( (2.01,-2.01) )
False
>>>hash( (-1,1) ) == hash( (1,-1) ) 
False

1
那会是什么样的特性呢?我倾向于说这显然不是一个特性,因为你希望你的哈希函数没有这些属性。那么你的问题是什么? - Niklas B.
1
顺便说一下,你可能想写成(-1,),因为否则多余的一对括号是冗余的。 - Niklas B.
好的,hash(-1) == hash(-2) 之所以成立并不是一个 bug,而且有其原因(请参考上面的链接)。那么这个现象是否也有类似的解释呢,还是只是一种奇怪的现象?这就是我的问题。 - Tom Stephens
2
这并不是一个 bug,因为哈希冲突是无法避免的。但它肯定不是一个特性,只是一种解决方法/实现细节。它很可能也与具体实现相关,所以与 Python 本身关系不大,更多地与 cpython 实现有关(你在 pypy 或 ironpython 中尝试过吗?)。 - Niklas B.
1
@TomStephens 请检查我的答案,以获得全面的解释。 - thefourtheye
2个回答

3

这不是一个特性,而是一个巧合。哈希冲突会发生。

Python的整数哈希很愚蠢,元组哈希通常还好。

Python的字典实现旨在与不良哈希值卡斯特后重新哈希,因此并不太重要。


2
巧合的是,我刚好在本周早些时候查找了Python如何进行元组哈希的方式,因为我正在考虑编写一个独立于实现/语言的JSON数据哈希。我发现这相当有趣:http://hg.python.org/cpython/file/6e04027ed53e/Objects/tupleobject.c#l341 - Mike Graham

2
在查看哈希逻辑之前,让我们先了解一些细节。
1. Python整数的哈希值将是数字本身。 2. 唯一的例外是-1。因为-1在内部用于指示错误情况。因此,-1的哈希值将为-2。(对于-2,它仍将是-2。) 有了这个理解,我们可以回答您的示例2、3和5。
示例2:-1的哈希值== -2的哈希值。所以它是真的。
示例3:与示例2的原因相同
示例5:-1和1的哈希值不同(分别为-2和1)。这就是为什么结果为False的原因。
案例示例4中,浮点数的哈希值与数字本身不同,因为哈希值应该是整数。而数字在内存中的表示方式也不同于它们本身。(2.01在内存中并非以2.01的形式存储)。因此,它们的哈希值不同是可以接受的。
回答示例1,让我们看一些代码。根据元组哈希实现,让我们使用Python程序计算哈希值。
x, hash_mult = int("0x345678", 16), 1000003
x, hash_mult = (x ^ 2) * hash_mult, hash_mult + 82522
x = (x ^ -2) * hash_mult
print(x + 97531)                                   # -3713082714466793269

x, hash_mult = int("0x345678", 16), 1000003
x, hash_mult = (x ^ -2) * hash_mult, hash_mult + 82522
x = (x ^ 2) * hash_mult
print(x + 97531)                                   # -3713082714466793269

print(hash((-2, 2)))                               # -3713082714466793269

注意: 这不仅适用于-2, 2,而是适用于所有整数,除了上述情况和所有8的倍数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接