我想subclass
dict
在 python 中使子类的所有字典都是不可变的。
我不明白它是如何__hash__
影响不变性的,因为在我的理解中它只是表示对象的相等或不相等!
那么,可以__hash__
用来实现不变性吗?如何 ?
更新:
目标是来自 API 的公共响应可用作 dict,它必须作为全局变量共享。那么,无论如何,它都需要完好无损?
我想subclass
dict
在 python 中使子类的所有字典都是不可变的。
我不明白它是如何__hash__
影响不变性的,因为在我的理解中它只是表示对象的相等或不相等!
那么,可以__hash__
用来实现不变性吗?如何 ?
更新:
目标是来自 API 的公共响应可用作 dict,它必须作为全局变量共享。那么,无论如何,它都需要完好无损?
我找到了官方参考:被拒绝的 PEP 中包含的建议。
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
归属: http: //www.python.org/dev/peps/pep-0351/
那么,可以
__hash__
用来实现不变性吗?
不,它不能。无论其__hash__
方法做什么,都可以使对象可变(或不可变)。
不可变对象 和 之间的关系__hash__
是,由于不可变对象无法更改,因此返回的值在__hash__
构造后保持不变。对于可变对象,这可能是也可能不是(推荐的做法是这些对象根本无法散列)。
如需进一步讨论,请参阅问题 13707:澄清hash()
选区。
关于哈希性和可变性之间的关系:
为了有用,哈希实现需要满足以下属性:
比较相等的两个对象的哈希值==
必须相等。
哈希值可能不会随时间变化。
这两个属性意味着可散列的类在比较实例时不能考虑可变属性,并且相反,在比较实例时确实考虑了可变属性的类是不可散列的。不可变类可以在不影响比较的情况下进行哈希处理。
所有内置的可变类型都不是可散列的,所有不可变的内置类型都是可散列的。这主要是上述观察的结果。
默认情况下,用户定义的类定义基于对象标识的比较,并使用id()
as hash。它们是可变的,但在比较实例时不考虑可变数据,因此可以将它们设为可散列的。
使一个类可散列并不会以某种神奇的方式使其不可变。相反,要在保持原始比较运算符的同时以合理的方式使字典可散列,您首先需要使其不可变。
编辑:关于您的更新:
有几种方法可以提供等效的全局不可变字典:
请改用collections.namedtuple()
实例。
使用具有只读属性的用户定义类。
我通常会这样做:
_my_global_dict = {"a": 42, "b": 7}
def request_value(key):
return _my_global_dict[key]
通过前导下划线,您可以清楚地表明这_my_global_dict
是应用程序代码不涉及的实现细节。请注意,如果字典值恰好是可变对象,则此代码仍允许修改它们。如有必要,您可以通过返回copy.copy()
s 或s 个值来解决此问题。copy.deepcopy()
在frozendict中,hash 在被拒绝的PEP 416之后简单地实现:
def __hash__(self):
try:
fs = frozenset(self.items())
except TypeError:
hash = -1
else:
hash = hash(fs)
if hash == -1:
raise TypeError("Not all values are hashable.")
return hash
PS:我是包的新维护者。