我正在尝试构建一组对象的实例,但是添加某些对象的实例会产生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派生的对象的一组实例?
答案 0 :(得分:5)
为了将东西放入一套,它们应该是可以清洗的。例如,元组是可清除的,而列表则不是。您可以通过为其提供__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
课程不耐用。
答案 1 :(得分:4)
如果需要,您的类可以定义__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
类互操作,因为这是对不继承或定义其他版本的类进行散列和比较的默认实现(因为您继承了不同的版本)来自__eq__
的{{1}},除非您再次覆盖它。)
DictMixin
是x is self
的更快,更直接,更简洁的表达,因为 是id(x) == id(self)
运算符的含义 - is
(即同一个对象)。
因此,id
被迫与您的应用程序的问题a==b
意味着相同的事实?如果是这样,那么集合对于所述应用程序是不可用的,您需要考虑其他一些完全不同的数据结构(不是基于散列的数据结构,因为没有a is b
覆盖,您无法使散列正常工作)。