我有一个只根据其属性内容进行比较的类,因此具有相同值的两个对象是等效的。
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会给我一个秒元素,相当于第一个。有没有办法解决这个问题?
答案 0 :(得分:0)
对象的哈希值在对象第一次存储在集合的哈希表中时存储。即使对象发生变异,它也不会更新。
初始哈希值hash("a(value=1)")
正在使用而不是hash("a(value=2)")
。
这是为什么可变项目从未被集合首先采取的原因之一;除了你使用后门。
修改a1.value = 1
将对象恢复为与集合所包含的匹配相同的匹配。
答案 1 :(得分:0)
默认的python集类型不支持可变对象。您可以设计一个接口,该接口保留对包含其实例的容器的一组弱引用。然后,实例可以在哈希值发生变化时向容器发出信号。你需要:
容器在添加实例时调用的实例的方法
实例在哈希值更改时调用的容器上的方法
检测哈希值更改,可能会覆盖类上的 setattr 。