Python 3中的不可变字典:如何使keys(),items()和values()字典视图不可变

15

简短版:在Python 3中,如何最好地覆盖dict.keys()等操作,以防止意外修改(本应是)不可变的字典?

我曾经问过一个关于在Python中哈希不可变字典的问题。此后,我已经创建了一个我满意的不可变、可哈希字典。但是,我发现它有一个漏洞:由keys()items()values()返回的字典视图仍然允许我意外地修改我的(本应是)不可变字典。

我在Stack Overflow上找到的唯一一个关于字典视图的问题是Python create own dict view of subset of dictionary,但那似乎与我的问题没有太多关系,而“冻结字典”是什么?的答案似乎没有涉及覆盖keys()等操作。

像这样做是否会防止我意外地修改不可变字典的键等内容?

class FrozenCounter(collections.Counter):
    "Model an hashable multiset as an immutable dictionary."
    # ...
    def keys(self):
        return list(super().keys())
    def values(self):
        return list(super().values())
    def items(self):
        return list(super().items())

从回答中得出的结论

主要是我不会读。

dictviews 无法修改字典。在Python 3文档中,我误读了“They provide a dynamic view on the dictionary’s entries, which means that when the dictionary changes, the view reflects these changes”为“当视图更改时,字典反映这些更改”,显然这不是文档所说的。

2个回答

6
在Python 2.x中,视图不允许您改变底层对象:
>>> a = { 'a' : 1 }
>>> a.keys()[0] = 'b'
>>> a
{'a': 1}
>>> a.values()[0] = 'b'
>>> a
{'a': 1}

在Python 3.x中,修改视图会引发TypeError错误:
>>> a = { 'a':1}
>>> a.keys()[0] = 'b'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'dict_keys' object does not support item assignment

@user1202136:a.keys()[0]不是一个相关的测试:正如错误消息所指示的那样,它只是说您可以设置a.keys()的元素#0。它并没有说您不能修改它。问题在于视图没有“元素#0”(它们大多是具有任意顺序的对象集合)。 - Eric O. Lebigot
@EOL 你是对的:a = { 'a' : set() }; print a; a.values()[0].add("0"); print a - user1202136

0

这可能是一个不好的想法,因为它打破了那些方法首先返回视图的假设,并用不再更新以匹配底层字典的可变对象替换了它们。

你的视图如何能够改变你的字典?视图不支持项目分配或删除,所以我不认为它们可以改变底层字典。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接