一组可变对象变得糊涂了

时间:2017-05-16 12:40:06

标签: python set mutable

我有一个只根据其属性内容进行比较的类,因此具有相同值的两个对象是等效的。

class a(object):
    def __init__(self, value):
        self.value = value
    def __repr__(self):
        return 'a(value={})'.format(self.value)
    def __hash__(self):
        return hash(self.__repr__())
    def __eq__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return self.value == other.value
    def __ne__(self, other):
        return not self.__eq__(other)

当我创建类的对象并将其添加到集合时,它会正确添加。然后我创建一个具有不同值的第二个对象,并修改第一个对象以匹配第二个对象。该集合现在显示修改后的对象,并且a1和a2之间的比较正确地表示为True。

如果我现在尝试在a1或a2的集合中搜索,即使明确添加a1并且a2比较True,该集合也无法找到它们。

# create the object and a set with it
a1 = a(1)
a_set = set([a1])
print('Elements in set are: {}'.format(','.join([element.__repr__() for element in a_set])))

# build a new object and modify the original object to be identical to the second
a2 = a(2)
a1.value = 2
print('Elements in set are: {}'.format(','.join([element.__repr__() for element in a_set])))

# object compare fine
print('{} == {} is {}'.format(a1, a2, a1 == a2))

# none of the object are in the set (even if a1 was added to the set)
print('{} in set is {}'.format(a1, a1 in a_set))
print('{} in set is {}'.format(a2, a2 in a_set))
print('Elements in set are: {}'.format(','.join([element.__repr__() for element in a_set])))

我明白这可能是因为a1存储在哈希对应的原始值下的集合中,而不是修改后的值,但问题是在集合中添加a2会给我一个秒元素,相当于第一个。有没有办法解决这个问题?

2 个答案:

答案 0 :(得分:0)

对象的哈希值在对象第一次存储在集合的哈希表中时存储。即使对象发生变异,它也不会更新。

初始哈希值hash("a(value=1)")正在使用而不是hash("a(value=2)")

这是为什么可变项目从未被集合首先采取的原因之一;除了你使用后门

修改a1.value = 1将对象恢复为与集合所包含的匹配相同的匹配。

答案 1 :(得分:0)

默认的python集类型不支持可变对象。您可以设计一个接口,该接口保留对包含其实例的容器的一组弱引用。然后,实例可以在哈希值发生变化时向容器发出信号。你需要:

  • 容器在添加实例时调用的实例的方法

  • 实例在哈希值更改时调用的容器上的方法

  • 检测哈希值更改,可能会覆盖类上的 setattr