How to change behavior of dict() for an instance How to change behavior of dict() for an instance python python

How to change behavior of dict() for an instance


Nothing wrong with your approach, but this is similar to the Autovivification feature of Perl, which has been implemented in Python in this question. Props to @nosklo for this.

class RecursiveDict(dict):    """Implementation of perl's autovivification feature."""    def __getitem__(self, item):        try:            return dict.__getitem__(self, item)        except KeyError:            value = self[item] = type(self)()            return value>>> a = RecursiveDict()>>> a[1][2][3] = 4>>> dict(a){1: {2: {3: 4}}}

EDIT

As suggested by @Rosh Oxymoron, using __missing__ results in a more concise implementation. Requires Python >= 2.5

class RecursiveDict(dict):    """Implementation of perl's autovivification feature."""    def __missing__(self, key):        value = self[key] = type(self)()        return value


Do you want just to print it like a dict ? use this:

from collections import defaultdictclass RecursiveDict(defaultdict):    '''    A recursive default dict.    >>> a = RecursiveDict()    >>> a[1][2][3] = 4    >>> a.dictify()    {1: {2: {3: 4}}}    >>> dict(a)    {1: {2: {3: 4}}}    '''    def __init__(self):        super(RecursiveDict, self).__init__(RecursiveDict)    def dictify(self):        '''Get a standard dictionary of the items in the tree.'''        return dict([(k, (v.dictify() if isinstance(v, dict) else v))                     for (k, v) in self.items()])    def __dict__(self):        '''Get a standard dictionary of the items in the tree.'''        print [(k, v) for (k, v) in self.items()]        return dict([(k, (dict(v) if isinstance(v, dict) else v))                     for (k, v) in self.items()])    def __repr__(self):        return repr(self.dictify())

Maybe you are looking for __missing__ :

class RecursiveDict(dict):    '''    A recursive default dict.    >>> a = RecursiveDict()    >>> a[1][2][3] = 4    >>> a    {1: {2: {3: 4}}}    >>> dict(a)    {1: {2: {3: 4}}}    '''    def __missing__(self, key):        self[key] = self.__class__()        return self[key]


edit: As ironchefpython pointed out in comments, this isn't actually doing what I thought it did, as in my example b[1] is still a RecursiveDict. This may still be useful, as you essentially get an object pretty similar Rob Cowie's answer, but it is built on defaultdict.


You can get the behavior you want (or something very similar) by overriding __repr__, check this out:

class RecursiveDict(defaultdict):    def __init__(self):        super(RecursiveDict, self).__init__(RecursiveDict)    def __repr__(self):        return repr(dict(self))>>> a = RecursiveDict()>>> a[1][2][3] = 4>>> a             # a looks like a normal dict since repr is overridden{1: {2: {3: 4}}}>>> type(a)<class '__main__.RecursiveDict'>>>> b = dict(a)>>> b             # dict(a) gives us a normal dictionary{1: {2: {3: 4}}}>>> b[5][6] = 7   # obviously this won't work anymoreTraceback (most recent call last):  File "<stdin>", line 1, in <module>KeyError: 5>>> type(b)<type 'dict'>

There may be a better way to get to a normal dictionary view of the defaultdict than dict(self) but I couldn't find one, comment if you know how.