python 定义 `__eq__` 的类型是不可散列的吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1608842/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Types that define `__eq__` are unhashable?
提问by Ram Rachum
I had a strange bug when porting a feature to the Python 3.1 fork of my program. I narrowed it down to the following hypothesis:
在将功能移植到我的程序的 Python 3.1 分支时,我遇到了一个奇怪的错误。我将其缩小为以下假设:
In contrast to Python 2.x, in Python 3.x if an object has an __eq__
method it is automatically unhashable.
与 Python 2.x 不同的是,在 Python 3.x 中,如果一个对象有一个__eq__
方法,它会自动成为不可散列的。
Is this true?
这是真的?
Here's what happens in Python 3.1:
以下是 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'
The follow-up question is, how do I solve my personal problem? I have an object ChangeTracker
which stores a WeakKeyDictionary
that points to several objects, giving for each the value of their pickle dump at a certain time point in the past. Whenever an existing object is checked in, the change tracker says whether its new pickle is identical to its old one, therefore saying whether the object has changed in the meantime. Problem is, now I can't even check if the given object is in the library, because it makes it raise an exception about the object being unhashable. (Cause it has a __eq__
method.) How can I work around this?
后续问题是,我如何解决我的个人问题?我有一个ChangeTracker
存储WeakKeyDictionary
指向多个对象的对象,在过去的某个时间点为每个对象提供泡菜转储的值。每当签入现有对象时,更改跟踪器都会说明其新泡菜是否与旧泡菜相同,因此会说明该对象在此期间是否已更改。问题是,现在我什至无法检查给定的对象是否在库中,因为它会引发关于对象不可散列的异常。(因为它有一个__eq__
方法。)我该如何解决这个问题?
采纳答案by Martin v. L?wis
Yes, if you define __eq__
, the default __hash__
(namely, hashing the address of the object in memory) goes away. This is important because hashing needs to be consistent with equality: equal objects need to hash the same.
是的,如果您定义了__eq__
,则默认值__hash__
(即对内存中对象的地址进行散列处理)将消失。这很重要,因为散列需要与相等一致:相等的对象需要散列相同。
The solution is simple: just define __hash__
along with defining __eq__
.
解决方案很简单:只需定义__hash__
与定义一起__eq__
。
回答by newacct
This paragraph from http://docs.python.org/3.1/reference/datamodel.html#object.hash
这一段来自http://docs.python.org/3.1/reference/datamodel.html#object。散列
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__ = <ParentClass>.__hash__
. Otherwise the inheritance of__hash__()
will be blocked, just as if__hash__
had been explicitly set to None.
如果覆盖的类
__eq__()
需要保留__hash__()
来自父类的实现 ,则必须通过设置__hash__ = <ParentClass>.__hash__
. 否则继承__hash__()
将被阻塞,就像__hash__
被显式设置为 None 一样。
回答by Mark Rushakoff
Check the Python 3 manual on object.__hash__
:
检查 Python 3 手册object.__hash__
:
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.
如果一个类没有定义一个
__eq__()
方法,那么它也不应该定义一个__hash__()
操作;如果它定义__eq__()
但不是__hash__()
,它的实例将不能用作可散列集合中的项目。
Emphasis is mine.
重点是我的。
If you want to be lazy, it sounds like you can just define __hash__(self)
to return id(self)
:
如果你想偷懒,听起来你可以定义__hash__(self)
return id(self)
:
User-defined classes have
__eq__()
and__hash__()
methods by default; with them, all objects compare unequal (except with themselves) andx.__hash__()
returnsid(x)
.
用户定义的类默认有
__eq__()
和__hash__()
方法;与它们相比,所有对象都比较不相等(除了它们自己)并x.__hash__()
返回id(x)
.
回答by falstro
I'm no python expert, but wouldn't it make sense that, when you define a eq-method, you also have to define a hash-method as well (which calculates the hash value for an object) Otherwise, the hashing mechanism wouldn't know if it hit the same object, or a different object with just the same hash-value. Actually, it's the other way around, it'd probably end up computing different hash values for objects considered equal by your __eq__
method.
我不是 python 专家,但是当你定义一个 eq 方法时,你还必须定义一个哈希方法(它计算对象的哈希值),否则,哈希机制不知道它是击中了同一个对象,还是具有相同散列值的不同对象。实际上,情况正好相反,它可能最终会为您的__eq__
方法认为相等的对象计算不同的哈希值。
I have no idea what that hash function is called though, __hash__
perhaps? :)
我不知道那个哈希函数叫什么,__hash__
也许吧?:)