我想subclass
dict
在Python中,这样的子类的所有字典是不可变的。如何在python中创建一个不可变的字典?
我不明白怎么做__hash__
影响不变性,因为在我的理解,它只是意味着该平等或对象的非平等!
那么,__hash__
可以用来实现不变性?怎么样 ?
更新:
目的是从API常见的反应可作为一个字典,其具有作为全局变量被共享。那么,无论如何,这都需要保持完整。
我想subclass
dict
在Python中,这样的子类的所有字典是不可变的。如何在python中创建一个不可变的字典?
我不明白怎么做__hash__
影响不变性,因为在我的理解,它只是意味着该平等或对象的非平等!
那么,__hash__
可以用来实现不变性?怎么样 ?
更新:
目的是从API常见的反应可作为一个字典,其具有作为全局变量被共享。那么,无论如何,这都需要保持完整。
我发现了一个官方参考:
class imdict(dict):
def __hash__(self):
return id(self)
def _immutable(self, *args, **kws):
raise TypeError('object is immutable')
__setitem__ = _immutable
__delitem__ = _immutable
clear = _immutable
update = _immutable
setdefault = _immutable
pop = _immutable
popitem = _immutable
最后,工作真棒,加上一个更有信心的来源。 –
那么,
__hash__
可以用来实现不变性吗?
不,它不能。无论对象的方法如何,该对象都可以变为可变的(或不变)。
不可变对象与__hash__
之间的关系是,由于无法更改不可变对象,所以__hash__
返回的值在构建后保持不变。对于可变对象,这可能会也可能不是这种情况(推荐的做法是这些对象根本无法散列)。
有关进一步的讨论,请参阅Issue 13707: Clarify hash()
constency period。
那么,默认情况下,用户定义的类都是可变和可哈希的,但哈希将始终保持不变! –
@SvenMarnach:你说的是真的。我说的也是如此。 TBH,我没有看到你的推理线路在哪里...... – NPE
我只是建议你的答案的最后一句话有些不完整。关于不变性和可否性之间的关系还有更多。 –
关于hashability和可变性之间的关系:
为了有用,散列实现需要满足以下性质:
使用==
必须是比较相等的两个对象的哈希值等于。
散列值可能不会随时间而改变。
这两个属性意味着比较实例时,哈希的类不能采取可变的特性考虑,并通过对位的是里面做类采取可变属性考虑在内时,比较实例不是可哈希。不可变的类可以进行哈希,没有任何比较的影响。
所有内置的可变类型都不可散列,并且所有不可变的内置类型都是可散列的。这主要是上述观察的结果。
默认情况下,用户定义的类根据对象标识定义比较,并使用id()
作为散列。它们是可变的,但在比较实例时不会考虑可变数据,因此它们可以变为可散列的。
制作一个可拆分的类并不会使它在一些神奇的方式中不可变。相反,为了使字典在保持原始比较运算符的同时以合理的方式可散列化,首先需要使它不可变。
编辑:关于你提到的更新:
有几种方法,以提供全球不可改变字典相当于:
使用collections.namedtuple()
实例,而不是。
使用具有只读属性的用户定义的类。
我通常像这样的东西去:
_my_global_dict = {"a": 42, "b": 7}
def request_value(key):
return _my_global_dict[key]
通过领先的下划线,你清楚地表明_my_global_dict
是一个实现细节不被应用程序代码被感动。请注意,如果代码碰巧是可变对象,则此代码仍然允许修改字典值。如有必要,您可以通过返回copy.copy()
s或copy.deepcopy()
s来解决此问题。
所以,请给出一些可以使它成为'不可变'的代码? 由于这只是答案的一半! –
@YugalJindle:正如我以前多次说过的,使用不可变的字典很可能是您的问题的错误解决方案,但只有告诉我们您的问题实际是什么,我们才能告诉您。 (此外,我的印象是,你对一个好的解决方案并不感兴趣,并且你没有真正关注答案和评论。否则,你已经找到了一些示例代码,这在上面的评论中被链接了。) –
@YugalJindle:不,它当然不是你的情况中唯一的解决方案。再次,代码是针对您的问题的第二个评论中链接的不可变字典。 –
这已经被问了很多次之前(不幸的是,我没有方便的链接现在)。对于大多数问题,试图制作不可变的字典是错误的方法。你究竟想达到什么目的? –
这个链接怎么样:http://stackoverflow.com/q/2703599/623518 – Chris
我只会重写你的字典的__setitem __()'方法。但请注意,这并不能保证你的字典的值是不可变的(例如,你的值是列表,例如)。 –