我想在python中subclass
dict
,以便子类的所有字典都是不可变的。
我不明白__hash__
如何影响不变性,因为在我的理解中它只是表示对象的相等或不相等! / p>
那么,可以使用__hash__
来实现不变性吗?怎么样?
更新:
目标是来自API的常见响应可用作dict,它必须作为全局变量共享。那么,无论如何都需要完好无损?
答案 0 :(得分:9)
我找到了一个官方参考:
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
答案 1 :(得分:5)
那么,
__hash__
可以用来实现不变性吗?
不,它不能。无论__hash__
方法做什么,都可以使对象变得可变(或不变)。
不可变对象和__hash__
之间的关系是,由于无法更改不可变对象,__hash__
返回的值在构造后保持不变。对于可变对象,这可能是也可能不是这种情况(推荐的做法是这样的对象根本无法哈希)。
有关进一步的讨论,请参阅Issue 13707: Clarify hash()
constency period。
答案 2 :(得分:4)
关于可持续性和可变性之间的关系:
为了有用,哈希实现需要满足以下属性:
使用==
进行比较的两个对象的哈希值必须相等。
哈希值可能不会随时间而变化。
这两个属性意味着可比较的类在比较实例时不能将可变属性考虑在内,并且通过对比在比较实例时将可变属性考虑在内的类是不可清除的。不可变类可以制作,不会对比较产生任何影响。
所有内置的可变类型都不可清除,并且所有不可变的内置类型都是可清除的。这主要是上述观察结果。
默认情况下,用户定义的类根据对象标识定义比较,并使用id()
作为哈希。它们是可变的,但在比较实例时不会考虑可变数据,因此它们可以制作成可清除的。
使类hashable不会以某种神奇的方式使它变得不可变。相反,为了在保持原始比较运算符的同时以合理的方式编写字典,您首先需要使其不可变。
修改:关于您的更新:
有几种方法可以提供等效的全局不可变字典:
改为使用collections.namedtuple()
实例。
使用具有只读属性的用户定义类。
我通常会这样做:
_my_global_dict = {"a": 42, "b": 7}
def request_value(key):
return _my_global_dict[key]
通过前导下划线,您明确指出_my_global_dict
是应用程序代码无法触及的实现细节。请注意,如果字典值恰好是可变对象,则此代码仍允许修改它们。如有必要,您可以通过返回值copy.copy()
或copy.deepcopy()
来解决此问题。