title: KeyError from dict where Key is present - Python
link: http://jj.isgeek.net/2016/01/keyerror-from-dict-where-key-is-present/
author: Jj
description: 
post_id: 1026
date: 2016/01/09 02:35:09
created_gmt: 2016/01/09 07:35:09
comment_status: open
slug: keyerror-from-dict-where-key-is-present

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](http://stackoverflow.com/a/3387975) 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.