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

Ram*_*hum 66 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'
Run Code Online (Sandbox Code Playgroud)

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

Mar*_*wis 65

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

解决方案很简单:只需定义__hash__定义即可__eq__.

  • @ cool-RR:在`__hash __()`中使用`id(self)`肯定是错误的,除非你定义`__eq __()`来按对象标识进行比较(这似乎没有意义).那么用真正的`__eq __()`实现来更新你的问题呢,这样我们可以建议`__hash __()`补充它? (26认同)
  • 这不是一个好的答案 - 它不仅仅是默认的哈希消失 - 它是_any继承的hash_. (5认同)

new*_*cct 22

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

如果覆盖的类__eq__() 需要保留__hash__()父类的实现 ,则必须通过设置明确告知解释器__hash__ = <ParentClass>.__hash__.否则__hash__()将阻止继承,就像__hash__已经显式设置为None一样.


Mar*_*off 8

检查 Python 3 手册object.__hash__

如果一个类没有定义__eq__()方法,那么它也不应该定义__hash__()操作;如果它定义了__eq__()但没有定义__hash__(),则其实例将不能用作可散列集合中的项目。

重点是我的。

如果你想偷懒,听起来你可以定义__hash__(self)return id(self)

用户定义的类默认有__eq__()和方法;__hash__()与它们相比,所有对象都比较不相等(除了它们自己)并x.__hash__()返回id(x)

  • 当然,重载 equals 运算符的唯一原因是两个不同的对象有时可以比较相等(如果不是,则不必重载它)。在这种情况下,“return id(self)”散列函数被破坏(相同的对象必须散列相同,请参阅 Martin 的答案)。“我不在乎”哈希函数将是“return 1”。这很简单并且满足所有条件(只是效率很低!) (5认同)