How to Make a Python Miltidict Class
In my previous post, I showed how to make a Python class immutable. This time around I will show you my attempt at making a "Multidict" class that behaves like a dictionary but can hold multiple values for each key. I accomplish this behavior by first inheriting the built in dict object and then changing some key methods to store more than one value per key.
By inheriting dict, we get a lot of the behaviors that we want for our Multidict. The following methods are all dict methods that we need to override in order to stop old values from getting replaced with new ones and instead stores all values for each key in a list.
class Multidict(dict):
The __setitem__ method controls the key assignment behavior which we need to change to not override the previous value but instead add a new value to the list of values if the key already exists.
def __setitem__(self, key, value):
if key in self:
self[key].append(value)
else:
dict.__setitem__(self, key, [value])
Dictionaries have a method called update that allows you to pass in either an iterable object or key word arguments (kwargs) in order to add all of the pairs to the dictionary. This is the same behavior we want to use when we initialize our Multidict so I wrote the update method then call it in __init__ in order to not repeat myself.
def update(self, iterable=(), **kwargs):
"""add kwargs or tuple iterable"""
if iterable:
if type(iterable) == dict:
iterable = iterable.items()
for key,val in iterable:
self[key] = val
if kwargs:
for key,val in kwargs.items():
self[key] = val
def __init__(self, iterable=(), **kwargs):
self.update(iterable, **kwargs)
def __delitem__(self, key):
if len(self[key]) > 1:
del self[key][0]
else:
dict.__delitem__(self, key)
For pop and popitem we also want to just affect the first item if there are more than one value for a key.
def pop(self, key):
if len(self[key]) > 1:
temp = self[key][0]
del self[key]
return temp
return dict.pop(self, key)
def popitem(self, key):
if len(self[key]) > 1:
temp = key, [self[key][0]]
del self[key][0]
return temp
return dict.popitem(self, key)
def values(self):
return [val for vals in dict.values(self) for val in vals]
Inheriting dict
By inheriting dict, we get a lot of the behaviors that we want for our Multidict. The following methods are all dict methods that we need to override in order to stop old values from getting replaced with new ones and instead stores all values for each key in a list.class Multidict(dict):
__setitem__ Methods
The __setitem__ method controls the key assignment behavior which we need to change to not override the previous value but instead add a new value to the list of values if the key already exists.
def __setitem__(self, key, value):
if key in self:
self[key].append(value)
else:
dict.__setitem__(self, key, [value])
__init__ and update Method
def update(self, iterable=(), **kwargs):
"""add kwargs or tuple iterable"""
if iterable:
if type(iterable) == dict:
iterable = iterable.items()
for key,val in iterable:
self[key] = val
if kwargs:
for key,val in kwargs.items():
self[key] = val
def __init__(self, iterable=(), **kwargs):
self.update(iterable, **kwargs)
__delitem__ Method
My __delitem__ method prevents all values from being deleted when there are more than one value stored for the key. It instead deletes the first value while leaving the rest. If only one value is stored, it uses the old dict __delitem__ method.def __delitem__(self, key):
if len(self[key]) > 1:
del self[key][0]
else:
dict.__delitem__(self, key)
pop and popitem Methods
For pop and popitem we also want to just affect the first item if there are more than one value for a key.def pop(self, key):
if len(self[key]) > 1:
temp = self[key][0]
del self[key]
return temp
return dict.pop(self, key)
def popitem(self, key):
if len(self[key]) > 1:
temp = key, [self[key][0]]
del self[key][0]
return temp
return dict.popitem(self, key)
values Method
In order for our values method to output a list of just our values, we need to flatten out all our lists inside our Multidict keys.def values(self):
return [val for vals in dict.values(self) for val in vals]
Awesome job, super useful. For more info, visit this link: SEO Agency in Chennai
ReplyDelete