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