繁体   English   中英

Python:为什么我可以将可变对象放入dict或set中?

[英]Python: why can I put mutable object in a dict or set?

给出以下示例,

class A(object):
    pass
a = A()
a.x = 1

显然,a是可变的,然后我将a放入集合中,

set([a])

成功了。 为什么我可以将可变对象(例如“ a”)放入集合/字典中? 设置/命令是否不应该只允许不可变的对象,以便它们可以识别对象并避免重复?

Python不会测试可变对象,而是测试可哈希对象。

自定义类实例默认情况下是可哈希的。 很好,因为此类的默认__eq__实现仅测试实例身份 ,并且哈希基于相同的信息。

换句话说,更改实例属性的状态并不重要,因为实例的身份始终是不可变的。

一旦实现考虑实例状态的__hash____eq__方法,您可能会遇到麻烦,应该停止对该状态进行__hash__ 只有这样,自定义类实例才不再适合存储在字典或集合中。

文档开始 ,要求它必须是可哈希的并且可以比较:

如果对象的哈希值在其生命周期内始终不变(需要使用hash ()方法),并且可以与其他对象进行比较(需要使用eq ()或cmp ()方法),则该对象是可哈希的。 比较相等的可哈希对象必须具有相同的哈希值。

散列性使对象可用作字典键和set成员,因为这些数据结构在内部使用散列值。

Python的所有不可变内置对象都是可哈希的,而没有可变容器(例如列表或字典)是可哈希的。 作为用户定义类实例的对象默认情况下是可哈希的 它们都比较不相等(除了它们本身),它们的哈希值是其id()。

您可以从最后一部分看到,用户定义的类(强调是我的)默认情况下是可哈希的

文档中没有提及set可变性要求:

class set([iterable])class Frozenset([iterable])返回一个新的set或Frozenset对象,其元素来自于iterable。 集合的元素必须是可哈希的。 为了表示集合集,内部集合必须是Frozenset对象。 如果未指定iterable,则返回一个新的空集。)

同样,对于dict ,要求键是可哈希的:

映射对象将可哈希值映射到任意对象。 映射是可变的对象。 当前只有一种标准映射类型,即字典。 (有关其他容器,请参见内置列表,集合和元组类,以及集合模块。)

经过更多研究后,我能够找出为什么我认为set和dict只允许将不可变对象用作条目和键的原因,这是不正确的。 我认为对我来说很重要,因为我敢肯定,对于Python来说,有些新人与我以前的疑问一样。 我以前有两个理由将不变性与哈希性混淆。 第一个原因是允许将所有内置的不可变对象(元组,frozenset ...)用作集合条目或dict键,而不允许所有内置的可变容器对象。 第二个原因实际上是这个问题的来源。 我正在读《 精通面​​向对象的Python 》一书。 在该部分说明了__hash__函数,它使读者认为不变性是哈希性的前提。

不变性的定义是针对对象,在创建对象后,您将无法更改其现有属性的值或创建新属性。 因此,它与哈希性无关,后者要求对象定义其__hash__()__eq__()方法,并且其哈希值在其生命周期内是不可变的。 实际上,可哈希对象就其哈希值而言是不变的。 我想这就是这两个概念如此频繁混淆的原因之一。

添加成员时, id不会更改。 因此没有理由不起作用。

class A(object):
    pass
a = A()
print(id(a))

a.x = 1
print(id(a))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM