Python: freezing dict keys after creating

Is it possible to β€œfreeze” a python dict after creation so that it is not possible to add new keys to it? One could modify the existing key values.

If not, how do you know when you change an existing pair of key values, and when you add a new one?

+7
python immutability dictionary keyvaluepair
source share
2 answers

Maybe something like this:

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 

Note that you can also overwrite other methods, including __delitem__ , update , setdefault , pop and popitem , as they can change the dictionary.


If you are interested in locking the dictionary completely, you can use types.MappingProxyType , which provides read-only browsing in your dictionary. Once you have created your regular dictionary, you can simply create a mapping proxy that simply does not have any assignment / update function. You can also get rid of any link to the source dictionary (the mapping will contain one) so that it is not used for its further update:

 >>> 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'}) 

Or just in one line, without reference to the source dictionary:

 >>> 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 
+8
source share

This is not possible with the "vanilla" dict. You probably want to subclass collections.MutableMapping .,

Unconfirmed code follows

 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) 
+3
source share

All Articles