关于字典:Python:创建后冻结字典键

Python: Freeze dict keys after creation

本问题已经有最佳答案,请猛点这里访问。

是否可以在创建后"冻结"python dict,以便不可能向其添加新键?只能更改现有的键值。

如果没有,您如何知道何时更改现有的keyvalue对以及何时添加新的keyvalue对?


可能是这样的:

1
2
3
4
5
6
7
8
9
10
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> 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__updatesetdefaultpoppopitem,因为它们都可以修改字典。

如果您对完全锁定字典感兴趣,可以使用types.MappingProxyType,它为您的字典提供只读视图。一旦你创建了你的普通字典,你就可以创建一个映射代理,它只是没有任何分配/更新功能。然后您还可以去掉对原始字典的任何引用(映射将保留一个),以防止使用它进一步更新它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> 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'})

或者只是在一行中,从来没有引用过原始字典:

1
2
3
4
5
6
7
8
>>> 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


这是不可能的"香草"口述。你可能会想亚类collections.MutableMapping。…

未测试代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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)