Python 更改对象属性后如何保持用户定义对象集中元素的唯一性

Python 更改对象属性后如何保持用户定义对象集中元素的唯一性,python,set,mutability,Python,Set,Mutability,在将自定义实例的属性添加到集合中后,如何保留集合的唯一性特征来修改它们 如下面的代码所示: “杰克”和“约翰”在“名字”的平等性上是不同的。因此,它们都被添加到集合中 但是如果我把人的名字改成约翰,那么杰克和约翰的两个例子是相等的 然而,我的SET没有反映这一点,他们仍然认为这2个实例是不同的 注意:当用户定义的实例被添加到集合中后,有人意外地修改它们时,这会导致潜在的错误 我们是否有办法刷新集合,或者如何避免此问题 class Person: def __init__(self, n

在将自定义实例的属性添加到集合中后,如何保留集合的唯一性特征来修改它们

如下面的代码所示: “杰克”和“约翰”在“名字”的平等性上是不同的。因此,它们都被添加到集合中 但是如果我把人的名字改成约翰,那么杰克和约翰的两个例子是相等的 然而,我的SET没有反映这一点,他们仍然认为这2个实例是不同的

注意:当用户定义的实例被添加到集合中后,有人意外地修改它们时,这会导致潜在的错误

我们是否有办法刷新集合,或者如何避免此问题

class Person: 
    def __init__(self, name): 
        self.name = name 
    def __eq__(self, other):
        return self.name == other.name
    def __hash__(self):
        return hash(self.name)
jack = Person("Jack")
john = Person("John")
set1 = {jack, john}
jack.name = "John"
print(set1) // return 2 instance instead of 1. This is undesired behavior because now both jack & john are equal 

您创建了两个不同的对象,如果打印
set1
,您将得到如下结果:
{,}

尽管它们的属性名称不同,但它们仍然是保存在不同内存空间中的两个不同对象。这就是为什么在将它们放入一个集合时,会出现两个对象都存在的意外行为

当您执行
jack.name=“John”
操作时,您只需更改属性
self.name

为了得到你想要的结果,你必须这样做:
set1={jack.name,john.name}


它将返回
{'John'}

您应该只使用不可变对象或引用的
集。请参阅:

拥有
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

您的
集合中的
Person
对象是可变的,但是您已经实现了自己的哈希函数和相等函数,绕过了安全性,正如您所指出的那样

我认为定义自定义散列函数和相等函数是可以的,但无论您对它们引用的内容做了什么,它们都应该返回相同的内容:例如,使用ID或内存地址进行散列

我建议从两个选项中选择一个,并强烈倾向于第一个选项:

选项A:不可变的
Person
在构造时使
Person
不可变。我最喜欢的方法是使用dataclass:

从数据类导入数据类
@数据类(冻结=真)
班长:
姓名:str
杰克=人(“杰克”)
约翰=人(“约翰”)
#注意,您不需要定义自己的哈希方法。
set1={杰克,约翰}
#这将失败:
jack.name=“Jaques”
考虑到这一点,但是如果你有很多不同的想法。
#如果要更改一个或几个字段,请尝试:
导入数据类
jaques=dataclasses.replace(jack,{“name”:“jaques”})
#但请注意,这是一个不同的对象。集合仍然与以前相同。
#您需要从集合中删除“jack”并添加“jaques”。
选项B:重新计算集 我应该指出,我认为这不是一个好主意,但您可以简单地运行:

set1={jack,john}

…再次,它将重新计算集合。

Python集合中的成员预期是不可变的。哈希值仅在插入时比较-集合中对象的突变不会触发集合中所有成员的唯一性属性的重新评估。要理解这一点,请尝试想象一个大集合。如果Python运行时允许动态uniqueness检查,每当更新某些内容时,它会一直忙于在集合中循环。另请参阅,感谢您指出。似乎我违反了“Hashable”对象的定义,该对象表示“其哈希值在其生命周期内不会更改”“。因为我的散列依赖于可以更改的名称属性,所以散列值将在其类似周期中更改。为了从解决方案提示中修复问题,任何属性都用于哈希,它们必须是只读的,以避免像我的案例那样的潜在错误。顺便说一句,“可哈希对象并不意味着不可变”,但“不可变意味着可哈希”。现在我已经清楚他的问题了谢谢你的回答。也许我的问题让人困惑。我的问题是,如果我们使用用户定义的对象作为集合中的元素,然后意外地修改这些用户定义对象的属性,那么如何避免集合的非唯一性特性的意外出现。我仍然希望保留用户定义的对象集,而不是名称属性集