定义`__eq__`的类型是不可用的?

时间:2009-10-22 17:46:32

标签: python hash python-3.x

将一个功能移植到我的程序的Python 3.1分支时,我遇到了一个奇怪的错误。我将其缩小到以下假设:

与Python 2.x相反,在Python 3.x中,如果对象具有__eq__方法,则它自动不可用。

这是真的吗?

这是Python 3.1中发生的事情:

>>> class O(object):
...     def __eq__(self, other):
...         return 'whatever'
...
>>> o = O()
>>> d = {o: 0}
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    d = {o: 0}
TypeError: unhashable type: 'O'

后续问题是,我该如何解决我的个人问题?我有一个对象ChangeTracker,它存储一个指向多个对象的WeakKeyDictionary,在过去的某个时间点为每个对象提供它们的值。每当签入现有对象时,更改跟踪器会说明其新的pickle是否与旧的pickle相同,因此在此期间说明对象是否已更改。问题是,现在我甚至无法检查给定对象是否在库中,因为它使得它引发了一个关于不可对象的对象的异常。 (因为它有一个__eq__方法。)我该如何解决这个问题?

4 个答案:

答案 0 :(得分:60)

是的,如果你定义__eq__,默认的__hash__(即散列内存中对象的地址)就会消失。这很重要,因为散列需要与相等一致:相等的对象需要散列相同的内容。

解决方案很简单:只需定义__hash__以及定义__eq__

答案 1 :(得分:22)

此段落来自http://docs.python.org/3.1/reference/datamodel.html#object.hash

  

如果某个类覆盖__eq__()   需要保留执行情况   来自父类的__hash__(),必须告诉解释器   明确地设置__hash__ = <ParentClass>.__hash__。否则   __hash__()的继承将是   被阻止,就好像__hash__一样   明确设置为无。

答案 2 :(得分:3)

查看object.__hash__上的Python 3手册:

  

如果某个类没有定义__eq__()方法,则它也不应定义__hash__()操作; 如果定义__eq__()但不定义__hash__(),则其实例将无法用作可展开集合中的项目。

重点是我的。

如果你想懒惰,听起来你可以定义__hash__(self)来返回id(self)

  

默认情况下,用户定义的类具有__eq__()__hash__()方法;与他们一起,所有对象比较不等(除了他们自己)和x.__hash__()返回id(x)

答案 3 :(得分:1)

我不是python专家,但是当你定义一个eq方法时,你也必须定义一个哈希方法(它计算一个对象的哈希值),这是没有意义的。否则,散列机制不会知道它是否匹配同一个对象,或者是否具有相同散列值的不同对象。实际上,它是相反的,它可能最终会为__eq__方法认为相同的对象计算不同的哈希值。

我不知道调用了什么哈希函数,__hash__也许? :)