【发布时间】:2019-05-24 19:44:45
【问题描述】:
我最近发现了一个有趣的观察结果,即有些事情会影响类的对象/实例的哈希性。我想知道如何以及为什么?
例如,我有一个名为ListNode的链表类:
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def __repr__(self):
if self.next:
return "{}->{}".format(self.val, repr(self.next))
else:
return "{}".format(self.val)
# def __eq__(self, other):
# if not self and not other:
# return True
# elif not self or not other:
# return False
# else:
# return self.val == other.val and self.next == other.next
# def __eq__(self, other):
# return str(self) == str(other)
请注意,我阻止了 __eq__ 方法。
现在,如果我创建一个实例:
A = ListNode(1)
B = ListNode(2)
C = ListNode(3)
A.next = B
B.next = C
print(hash(A))
然后它是可散列的,但是,每次运行它都会得到不同的输出数字。
现在,如果我取消阻止 __eq__ 方法,突然之间它就不再是可散列的了。为什么?
看来hash 方法会使用__eq__。又如何知道__eq__ 启用后它是不可哈希的?
附加:
如果我写__eq__方法只是比较两个链表的str版本(第二个__eq__方法),我认为这可以解决问题,因为通过将链表转换为string,它变成了可散列的数据,但我仍然收到unhashable 错误消息
谢谢!
根据@juanpa.arrivillaga 的评论:
__eq__ 将删除默认的__hash__ 方法,使其不可散列。
所以我添加了我自己的__hash__mehtod:
def __hash__(self):
return hash(id(self))
这解决了问题并在启用__eq__ 的情况下再次使ListNode 可散列。
【问题讨论】:
-
无论如何,因为如果你定义一个
__eq__,你必须定义一个兼容的__hash__。如果不定义__eq__,用户自定义类型默认基于身份哈希 -
@juanpa.arrivillaga 好的,在逻辑上它是有道理的。它确实有效。