I had this problem at work today. I had this snippet of Python code:
self.pop(key, None)
Which raised KeyError
. I inspected and I was inside an OrderedDict
subclass, so inside the pop()
method implementation I had this code:
if key in self:
del self[key]
Which was the originator of the exception raised. Took me a while to find out what the problem was until I noticed that the instance I was working on was not operating on the class where the pop()
call was made, but on a subclass that reimplemented __getitem__
. This made me open my eyes and spot the error.
This was my situation. I was looking at the code inside the delete_key
method, which is defined under MyBaseDict
, but I was on an instance of MyOtherDict
. Look at the following code:
class MyBaseDict(dict):
def delete_key(self, key):
del self[key]
class MyOtherDict(MyBaseDict):
def __init__(self, base, *args, **kwargs):
self.base = base
super(MyOtherDict, self).__init__(*args, **kwargs)
def __getitem__(self, key):
return self.base[key]
my_od = MyBaseOd()
my_od['a'] = 1
my_od['b'] = 2
assert my_od['b'] == 2
other_od = MyOtherOd(my_od)
assert other_od['b'] == 2
del other_od['b'] # Raises KeyError
At first sight it makes no sense that after I asserted that the key 'b'
exists I get a KeyError
trying to delete it! But what is happening is that the del
statement is calling an internal implementation of the base class, dict in this case. Which attempts to use an internal implementation of __getdict__
and not the user defined one.
The proper way to make a subclass of dict in Python requires you to subclass collections.MutableMapping. That will ensure that your del
statement uses the user defined dict protocol methods.
from collections import MutableMapping
class MyBaseDict(MutableMapping):
....
With the original inheritance change from dict to MutableMapping
the above script now works.