可变用户定义的类型和集合

时间:2015-10-18 05:02:44

标签: python hash

我有一个用例,要求我创建一组可变类型 对象,像这样:

class abc(object):
    def __init__(self):
        self.a = set(["a"])
    def __eq__(self, o):
        return self.a == o.a
a = abc()
b = abc()
print hash(a)
print hash(b)
print a == b
set([a]) == set([b])

阅读python文档,它说

  

“比较相等的对象具有相同的哈希值”

  

“如果一个类定义了可变对象并实现了__cmp__()__eq__()方法,那么它不应该实现__hash__(),因为hashable collection实现要求对象的哈希值是不可变的”< / p>

上面的示例将为a和b两者的相等和不同整数哈希打印true,但对于set相等则为false。文档建议将对象设置为不可用,但是我无法将其插入集合中。我的用法不正确吗?

python中的集合是不是要用于可变类型?

1 个答案:

答案 0 :(得分:2)

如果您将一个对象插入一个集合(或任何语言的任何基于散列的数据结构)然后对其进行变异,那么事情就会中断,因为新的散列值可能不再对应于它在数组中的位置。因此,例如,如果在变异之后插入了与前一个对象相同的另一个对象,python可能无法找到前一个对象,并且它将使两者都存在于集合中。这同样适用于二叉搜索树。

您需要:

  1. 只允许在构造函数中设置它们的值,使您的类不可变。
  2. 创建第二个不可变版本的类,第一个版本可以转换为(例如,通过将集合转换为frozensets并隐藏对成员的访问权限)。
  3. 使用数据结构,例如列表,您可以自由地改变对象,但检查成员资格(从而避免重复)需要花费O(n)时间。
  4. 让你的对象可以清洗,但要非常小心:每个影响其哈希和相等的突变都必须将其从所有集合(以及它是键的字典)中删除,改变它,然后将其放回去。