我最近发现了一个有趣的观察,即有些东西会影响类的对象/实例的可哈希性。我想知道如何以及为什么?
例如,我有一个名为 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__ 方法),我认为这可以解决问题,因为通过将链表转换为字符串
,它变成了可哈希数据,但我仍然收到unhashable
错误消息
谢谢!
According to @juanpa.arrivillaga's comment:
__eq__
将删除默认的 __hash__
方法,使其不可散列。
所以我添加了我自己的__hash__
方法:
def __hash__(self):
return hash(id(self))
这解决了问题,并在启用 __eq__
的情况下使 ListNode
再次可哈希。
最佳答案
If a class does not define an __eq__() method it should not define a __hash__() operation either; if it defines __eq__() but not __hash__(), its instances will not be usable as items in hashable collections.
(...)
A class that overrides __eq__() and does not define __hash__() will have its __hash__() implicitly set to None. When the __hash__() method of a class is None, instances of the class will raise an appropriate TypeError when a program attempts to retrieve their hash value, and will also be correctly identified as unhashable when checking isinstance(obj, collections.abc.Hashable). 1
引入 __eq__() 方法因此将 __hash__() 设置为 None。您可以添加自定义哈希,以允许上面的构造:
def __hash__(self):
return self.val
您可以在这里找到更多信息:https://docs.python.org/3/reference/datamodel.html#object.hash
关于python - 如何判断对象/实例是否可哈希,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56298727/