实例集合

1 投票
2 回答
4902 浏览
提问于 2025-04-15 17:51

我正在尝试创建一组对象的实例,但是添加某些对象的实例时出现了一个错误,叫做 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 个回答

4

要把东西放进一个集合(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 类是不可哈希的。

5

你的类可以选择定义一些方法,比如 __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 selfid(x) == id(self) 的一种更快、更直接、更简洁的表达方式,因为 就是 is 操作符的含义——表示对象的身份(即同一个对象)。

那么,a==b 被强制解释为和 a is b 一样的意思,这对你的应用程序来说是个问题吗?如果是的话,那么集合就不适合你的应用,你需要考虑其他完全不同的数据结构(一个不基于哈希的,因为如果没有重写 __eq__,你就无法正确使用哈希)。

撰写回答