__hash__ 和 __eq__ 如何用于集合的识别? 例如一些应该有助于解决一些多米诺拼图的代码:
class foo(object):
def __init__(self, one, two):
self.one = one
self.two = two
def __eq__(self,other):
if (self.one == other.one) and (self.two == other.two): return True
if (self.two == other.one) and (self.one == other.two): return True
return False
def __hash__(self):
return hash(self.one + self.two)
s = set()
for i in range(7):
for j in range(7):
s.add(foo(i,j))
len(s) // returns 28 Why?
如果我只使用 __eq__() len(s) 等于 49。没关系,因为据我了解对象(例如 1-2 和 2-1)不相同,但代表相同的多米诺骨牌。所以我添加了哈希函数。
现在它按照我想要的方式工作,但我不明白一件事:1-3 和 2-2 的散列应该相同,所以它们应该像同一个对象一样计算,不应该添加到集合中。但他们做到了!我卡住了。
请您参考如下方法:
dict/set 的相等性取决于 __eq__ 定义的相等性。但是,要求比较相等的对象具有相同的散列值,这就是您需要 __hash__ 的原因。参见 this question进行一些类似的讨论。
哈希本身并不能确定两个对象在字典中是否相同。散列就像一条“捷径”,只能以一种方式起作用:如果两个对象的散列不同,则它们肯定不相等;但如果它们具有相同的哈希值,它们仍然可能不相等。
在您的示例中,您定义了 __hash__ 和 __eq__ 来执行不同的操作。哈希仅取决于多米诺骨牌上数字的总和,但相等性取决于两个单独的数字(按顺序)。这是合法的,因为相同的多米诺骨牌仍然具有相同的哈希值。然而,就像我上面说的,这并不意味着等和多米诺骨牌会被认为是平等的。一些不相等的多米诺骨牌仍将具有相等的哈希值。但是相等性仍然由 __eq__ 确定,并且 __eq__ 仍然按顺序查看两个数字,因此这就是确定它们是否相等的因素。
在我看来,在你的情况下适当的做法是定义 __hash__ 和 __eq__ 以依赖于 ordered 对---即先比较两个数中较大的,再比较较小的。这意味着 2-1 和 1-2 将被视为相同。
