Home > Net >  How to make a dictonary not have delete methods?
How to make a dictonary not have delete methods?

Time:06-25

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.

  • Related