假设:
class T:
def __hash__(self):
return 1234
t1 = T()
t2 = T()
my_set = { t1 }
我希望以下内容能够打印True
:
print t2 in my_set
这不应该打印True
,因为t1
和t2
具有相同的哈希值。如何使in
的{{1}}运算符使用给定的哈希函数?
答案 0 :(得分:2)
您需要定义__eq__
方法,因为只有a is b
或相等a == b
的实例(除了具有相同的hash
)才会被set
识别为相等{1}}和dict
:
class T:
def __hash__(self):
return 1234
def __eq__(self, other):
return True
t1 = T()
t2 = T()
my_set = { t1 }
print(t2 in my_set) # True
data model on __hash__
(和the same documentation page for Python 2)解释了这一点:
__hash__
由内置函数
hash()
调用,对包含set
,frozenset
和dict. __hash__()
的散列集合成员的操作应返回一个整数。 唯一需要的属性是比较相等的对象具有相同的哈希值; 建议将对象组件的哈希值混合在一起,这些哈希值也通过打包对象在比较对象时起作用进入一个元组并对元组进行哈希处理。如果某个类未定义
__eq__()
方法,则不应定义__hash__()
操作;如果它定义__eq__()
但不定义__hash__()
,则其实例将不能用作可散列集合中的项目。如果一个类定义了可变对象并实现了__eq__()
方法,那么它不应该实现__hash__()
,因为hashable集合的实现要求键的哈希值是不可变的(如果对象的哈希值发生变化,它将会在错误的哈希桶中。)默认情况下,用户定义的类具有
__eq__()
和__hash__()
方法;与它们一起,所有对象都比较不相等(除了自己),x.__hash__()
返回一个适当的值,x == y
同时暗示x is y and hash(x) == hash(y)
。
(强调我的)
注意:在Python 2中,您还可以实现__cmp__
方法,而不是__eq__
。
答案 1 :(得分:0)
在伪代码中,当x in s
调用时, set .__的逻辑包含__()大致是:
h = hash(s) # This uses your class's __hash__()
i = h % table_size # This logic is internal to the hash table
if table[i] is empty: return False # Nothing found in the set
if table[i] is x: return True # Identity implies equality
if hash(table[i]) != h: return False # Hash mismatch implies inequality
return table[i] == x # This needs __eq__() in your class