I'm working on a project and I have a dictionary in Python. Due to this being an "append-only" dictionary, I need a way to disable .pop
, .popitem
, .clear
, etc. Is this possible in python?
I have tried:
mydict = dict()
#attempt 1:
mydict.pop = None
#Get error pop is read-only
#attempt 2:
del mydict.pop
#Get error pop is read-only
I have tried this on all delete methods with the same results.
CodePudding user response:
Subclass the dict()
class:
class MyDict(dict):
def clear(self):
pass
def pop(self):
pass
def popitem(self, *args):
pass
Now when you create your dict, create it using:
myDict = NewDict()
I quickly dumped this into the command line interpreter and it seems to work.
CodePudding user response:
Using inheritance to remove functionality violates Liskov substitution (a hypothetical dict
subclass would behave erroneously when treated as a dict
instance). And besides, I can easily just dict.clear(my_subclassed_dict_instance)
. The thing you're asking for is not, in Python terminology, a dict
and shouldn't masquerade as a subclass of one.
What you're looking for is a fresh class entirely. You want a class that contains a dict
, not one that is a dict
.
import collections.abc.Mapping
class MyAppendOnlyContainer(Mapping):
def __init__(self, **kwargs):
self._impl = kwargs
def __getitem__(self, key):
return self._impl[key]
def __setitem__(self, key, value):
self._impl[key] = value
def __iter__(self):
return iter(self._impl)
def __len__(self):
return len(self._impl)
# Plus whatever other functionality you need ...
Note that collections.abc.Mapping
requires __getitem__
, __iter__
, and __len__
(which your use case faithfully implements) and gives you get
, __contains__
, and several other useful dict
-like helper functions. What you have is not a dict
. What you have is a Mapping
with benefits.