实例集合
我正在尝试创建一组对象的实例,但是添加某些对象的实例时出现了一个错误,叫做 TypeError: unhashable instance
。下面是一个简单的例子:
from sets import Set
import random
from UserDict import DictMixin
class Item1(object):
pass
class Item2(DictMixin):
pass
item_collection = Set()
x = Item1()
y = Item2()
item_collection.add(x) # this works
print item_collection
item_collection.add(y) # this does not
print item_collection
为什么会出现这个错误呢?我该如何才能得到一个从 DictMixin 继承的对象实例的集合呢?
2 个回答
要把东西放进一个集合(set)里,这些东西必须是可哈希的。比如,元组(tuple)是可哈希的,而列表(list)则不是。你可以通过给你的对象添加一个 __hash__
方法来让它变得可哈希,这个方法会生成一个哈希键(也就是这个类实例的唯一标识符,取决于它所包含的数据)。
下面是一个尝试把列表放进集合的例子。
>>> x = [1,2,3]
>>> a=set()
>>> a.add(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
看起来你的 DictMixin
类是不可哈希的。
你的类可以选择定义一些方法,比如 __hash__
和比较方法(最重要的是 __eq__
),让它们之间保持一致和“稳定”。这意味着两个对象的相等性在它们的生命周期内不能变化,当然,每个对象的哈希值在其生命周期内也不能变化。
一致性要求是:a==b
必须意味着 hash(a)==hash(b)
(反过来不一定成立,实际上很少成立)。
如果你能接受这些要求,最简单的实现方式就是:
class Item2(DictMixin):
def __hash__(self): return hash(id(self))
def __eq__(self, x): return x is self
def __ne__(self, x): return x is not self
这样做的话,你的 Item1
类也会自动兼容,因为这是默认的哈希和比较实现,适用于那些没有继承或定义其他版本的类(除非你再次重写,否则你会从 DictMixin
继承一个不同版本的 __eq__
)。
x is self
是 id(x) == id(self)
的一种更快、更直接、更简洁的表达方式,因为 这 就是 is
操作符的含义——表示对象的身份(即同一个对象)。
那么,a==b
被强制解释为和 a is b
一样的意思,这对你的应用程序来说是个问题吗?如果是的话,那么集合就不适合你的应用,你需要考虑其他完全不同的数据结构(一个不基于哈希的,因为如果没有重写 __eq__
,你就无法正确使用哈希)。