Paul Biggar Paul Biggar - 1 year ago 120
Python Question

Python: How to "perfectly" override a dict

How can I make as "perfect" a subclass of dict as possible? The end goal is
to have a simple dict in which the keys are lowercase.

It would seem that should be some tiny set of primitives I can override to make
this work, but all my research and attempts have made it seem like this isn't
the case:

Here is my first go at it,
doesn't work at least, and no doubt there are
many minor subtle problems:

class arbitrary_dict(dict):
"""A dictionary that applies an arbitrary key-altering function
before accessing the keys."""

def __keytransform__(self, key):
return key

# Overridden methods. List from

def __init__(self, *args, **kwargs):
self.update(*args, **kwargs)

# Note: I'm using dict directly, since super(dict, self) doesn't work.
# I'm not sure why, perhaps dict is not a new-style class.

def __getitem__(self, key):
return dict.__getitem__(self, self.__keytransform__(key))

def __setitem__(self, key, value):
return dict.__setitem__(self, self.__keytransform__(key), value)

def __delitem__(self, key):
return dict.__delitem__(self, self.__keytransform__(key))

def __contains__(self, key):
return dict.__contains__(self, self.__keytransform__(key))

class lcdict(arbitrary_dict):
def __keytransform__(self, key):
return str(key).lower()

Answer Source

You can write an object that behaves like a dict quite easily with ABCs (Abstract Base Classes) from the collections module. It even tells you if you missed a method, so below is the minimal version that shuts the ABC up.

import collections

class TransformedDict(collections.MutableMapping):
    """A dictionary that applies an arbitrary key-altering
       function before accessing the keys"""

    def __init__(self, *args, **kwargs): = dict()
        self.update(dict(*args, **kwargs))  # use the free update to set keys

    def __getitem__(self, key):

    def __setitem__(self, key, value):[self.__keytransform__(key)] = value

    def __delitem__(self, key):

    def __iter__(self):
        return iter(

    def __len__(self):
        return len(

    def __keytransform__(self, key):
        return key

You get a few free methods from the ABC:

class MyTransformedDict(TransformedDict):

    def __keytransform__(self, key):
        return key.lower()

s = MyTransformedDict([('Test', 'test')])

assert s.get('TEST') is s['test']   # free get
assert 'TeSt' in s                  # free __contains__
                                    # free setdefault, __eq__, and so on

import pickle
assert pickle.loads(pickle.dumps(s)) == s
                                    # works too since we just use a normal dict

I wouldn't subclass dict (or other builtins) directly. It often makes no sense, because what you actually want to do is implement the interface of a dict. And that is exactly what ABCs are for.