关于python:定义`__eq__`的类型是不可用的?

Types that define `__eq__` are unhashable?

当我将一个特性移植到我的程序的python 3.1分支时,我遇到了一个奇怪的错误。我把范围缩小到以下假设:

与python 2.x不同,在python 3.x中,如果一个对象有一个__eq__方法,它将自动不可显示。

这是真的吗?

下面是在python 3.1中发生的事情:

1
2
3
4
5
6
7
8
9
10
>>> 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__方法。)我如何解决这个问题?


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

解决方案很简单:只需定义__hash____eq__


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

If a class that overrides __eq__()
needs to retain the implementation of
__hash__() from a parent class, the interpreter must be told this
explicitly by setting __hash__ =
.__hash__
. Otherwise the
inheritance of __hash__() will be
blocked, just as if __hash__ had been
explicitly set to None.


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

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.

重点是我的。

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

User-defined classes have __eq__() and __hash__() methods by default; with them, all objects compare unequal (except with themselves) and x.__hash__() returns id(x).


我不是Python专家,但在定义eq方法时,也必须定义哈希方法(它计算对象的哈希值),这是否有意义呢?否则,哈希机制就不知道它是命中同一对象,还是只命中具有相同哈希值的不同对象。实际上,它是相反的,它最终可能会为被您的__eq__方法认为相等的对象计算不同的散列值。

我不知道这个哈希函数叫什么,可能是__hash__?:)