何时是python对象';s哈希已计算,为什么-1的哈希不同?
从问题开始,我想知道python对象的哈希是什么时候计算的何时是python对象';s哈希已计算,为什么-1的哈希不同?,python,hash,Python,Hash,从问题开始,我想知道python对象的哈希是什么时候计算的 在实例的\uuuu init\uuuu时间 第一次调用\uuuu hash\uuuu() 每次调用\uuuu hash\uuuu()时,或 我还错过了其他机会吗 这可能因对象的类型而异吗 为什么散列(-1)=-2而其他整数等于它们的散列?来自: 哈希值-1是保留的(用于标记C实现中的错误)。 如果哈希算法生成这个值,我们只需使用-2即可 由于integer的哈希值是integer本身,因此它会立即更改。哈希值通常在每次使用时计算,因为您
\uuuu init\uuuu
时间\uuuu hash\uuuu()
\uuuu hash\uuuu()
时,或散列(-1)=-2
而其他整数等于它们的散列?来自:
哈希值-1是保留的(用于标记C实现中的错误)。
如果哈希算法生成这个值,我们只需使用-2即可
由于integer的哈希值是integer本身,因此它会立即更改。哈希值通常在每次使用时计算,因为您可以很容易地检查自己(请参见下文)。 当然,任何特定对象都可以自由缓存其哈希。例如,CPython字符串可以做到这一点,但元组不能做到这一点(参见示例,了解原因) CPython中的哈希值为-1。这是因为C没有异常,所以它需要使用返回值。当Python对象的
\uuuuu散列\uuuuu
返回-1时,CPython实际上会默默地将其更改为-2
你自己看看:
class HashTest(object):
def __hash__(self):
print('Yes! __hash__ was called!')
return -1
hash_test = HashTest()
# All of these will print out 'Yes! __hash__ was called!':
print('__hash__ call #1')
hash_test.__hash__()
print('__hash__ call #2')
hash_test.__hash__()
print('hash call #1')
hash(hash_test)
print('hash call #2')
hash(hash_test)
print('Dict creation')
dct = {hash_test: 0}
print('Dict get')
dct[hash_test]
print('Dict set')
dct[hash_test] = 0
print('__hash__ return value:')
print(hash_test.__hash__()) # prints -1
print('Actual hash value:')
print(hash(hash_test)) # prints -2
很容易看出#3选项适用于用户定义的对象。如果您改变对象,这允许哈希值发生变化,但是如果您将该对象用作字典键,则必须确保防止哈希值发生变化
>>> class C:
def __hash__(self):
print("__hash__ called")
return id(self)
>>> inst = C()
>>> hash(inst)
__hash__ called
43795408
>>> hash(inst)
__hash__ called
43795408
>>> d = { inst: 42 }
__hash__ called
>>> d[inst]
__hash__ called
字符串使用选项#2:它们计算一次哈希值并缓存结果。这是安全的,因为字符串是不可变的,因此哈希值永远不会更改,但是如果您将str
子类化,则结果可能不是不可变的,因此每次都会再次调用\uuuuuuuuuuu散列
方法。元组通常被认为是不可变的,因此您可能认为可以缓存哈希,但实际上元组的哈希取决于其内容的哈希,并且可能包含可变值
对于不相信str
的子类可以修改哈希的@max:
>>> class C(str):
def __init__(self, s):
self._n = 1
def __hash__(self):
return str.__hash__(self) + self._n
>>> x = C('hello')
>>> hash(x)
-717693723
>>> x._n = 2
>>> hash(x)
-717693722
3已退出,因为它在第一次调用时被缓存。我认为第二个选项是正确的,但我不确定我不会把它作为一个答案发布:)@rplnt:error;那只是指字典。它的散列将存储在字典中,但一般的散列不是这样。@ChrisMorgan实际上我不认为python
dict
为它的键缓存散列值。当然,个别类可以在其\uuuuu hash\uuuuu
函数中执行任何它们喜欢的操作,因此上面引用的文章说str
缓存其哈希值。@max:dict
是一个哈希表,根据定义必须存储其键的哈希值。这就是我所指的。“我所说的完全是真的。”克里斯姆博格当然同意。最初,我以为您是说dict
存储从键到其散列的映射,从而避免了重复调用hash(k)
的必要性——这一点不会发生。如果将包含可变值的元组作为参数传递给内置散列函数,则会引发TypeError异常。所以这不是元组不缓存其哈希值的原因。本章开头的链接提供了说明。另见。另外,您确定str子类没有缓存哈希吗?它似乎返回与str.hash相同的值,该值被自动缓存。@max,我为您添加了一个示例,说明str
子类的哈希值未被缓存。啊,是的,对。。我想我在想如果你不定义\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。