是否可以在创建后“冻结”Python字典,以使无法向其添加新键? 仅可以更改现有键的值。
如果不行,如何知道何时更改现有键值对,以及何时添加新键值对?
是否可以在创建后“冻结”Python字典,以使无法向其添加新键? 仅可以更改现有键的值。
如果不行,如何知道何时更改现有键值对,以及何时添加新键值对?
class FreezableDict (dict):
__frozen = False
def freeze (self):
self.__frozen = True
def __setitem__ (self, key, value):
if self.__frozen and key not in self:
raise ValueError('Dictionary is frozen')
super().__setitem__(key, value)
>>> x = FreezableDict({'foo': 'bar', 'baz': 'bla'})
>>> x
{'baz': 'bla', 'foo': 'bar'}
>>> x['asdf'] = 'fdsa'
>>> x
{'asdf': 'fdsa', 'baz': 'bla', 'foo': 'bar'}
>>> x.freeze()
>>> x['hello'] = 'world'
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
x['hello'] = 'world'
File "<pyshell#13>", line 8, in __setitem__
raise ValueError('Dictionary is frozen')
ValueError: Dictionary is frozen
__delitem__
、update
、setdefault
、pop
和 popitem
,因为它们都可以修改字典。
types.MappingProxyType
,它提供了对字典的只读视图。一旦创建了普通字典,就可以创建一个映射代理来使用它,映射代理不具备任何赋值/更新功能。还可以消除对原始字典的任何引用(映射将保留一个),以防止它被用于进一步更新:>>> x = {'foo': 'bar'}
>>> y = types.MappingProxyType(x)
>>> y
mappingproxy({'foo': 'bar'})
>>> x['baz'] = 'bla'
>>> y
mappingproxy({'baz': 'bla', 'foo': 'bar'})
>>> y['hello'] = 'world'
Traceback (most recent call last):
File "<pyshell#55>", line 1, in <module>
y['hello'] = 'world'
TypeError: 'mappingproxy' object does not support item assignment
>>> del x
>>> y
mappingproxy({'baz': 'bla', 'foo': 'bar'})
或者只在一行中,而不需要参考原始字典:
>>> x = types.MappingProxyType({'foo': 'bar', 'baz': 'bla'})
>>> x
mappingproxy({'baz': 'bla', 'foo': 'bar'})
>>> x['hello'] = 'world'
Traceback (most recent call last):
File "<pyshell#60>", line 1, in <module>
x['hello'] = 'world'
TypeError: 'mappingproxy' object does not support item assignment
types.MappingProxyType
- 绝对 +1 - Jon Clementsdictproxy
吗? - wimmappingproxy
的等效物。 - poketype(type('', (), {}).__dict__)({})
创建一个 dictproxy
,但是失败了 ;) - wim这不是使用"vanilla"字典的可能。你可能需要子类化collections.MutableMapping
...
未经测试的代码如下
class FrozenKeyDict(collections.MutableMapping):
"""Mapping which doesn't allow keys to be added/deleted.
It does allow existing key/value pairs to be modified.
"""
def __init__(self, *args, **kwargs):
self._frozen = False
self._dict = {}
super(FrozenKeyDict, self).__init__(*args, **kwargs)
self._frozen = True
def __getitem__(self, key):
return self._dict[key]
def __setitem__(self, key, value):
if self._frozen and key not in self._dict:
raise KeyError('must be one of %s' % list(self))
self._dict[key] = value
def __delitem__(self, key):
# modify to suit your needs ...
raise KeyError('Removing keys not supported')
def __iter__(self):
return iter(self._dict)
def __len__(self):
return len(self._dict)
list(self._dict)
列出items
,而不仅仅是键。也许使用list(self)
可以强制一点思考? - mgilsonlist(self)
将为空,因为所有数据都在 self._dict
而不是对象的 collections.MutableMapping
部分(选择其中一个)。 - Jon Clements__iter__(self)
只是返回 iter(self._dict)
,所以 list(self._dict)
和 list(self)
应该总是返回相同的结果。对吧?(__iter__
是 MutableMapping
接口的必需部分) 我们甚至可以在上面的成员测试中使用这个想法 -- if self._frozen and key not in self
,但我认为 dict.__contains__
可能比 MutableMapping.__contains__
更有效率,因为后者严重依赖于异常处理。 - mgilsonlist(self)
需要太多的思考(如果它让你感到困惑...)叹气 - mgilson
print 'already in' if key in dict else 'not here'
。 - enrico.bacis