creating a defaultlist in python creating a defaultlist in python python python

creating a defaultlist in python


On the example you give, you first try to retrieve a non-existing value on the list, as you do dl[2]['a'], Python first retrieve the third (index 2) element on the list, then proceed to get the element named 'a' on that object - therefore you have to implement your automatic extending behavior to the __getitem__ method as well, like this:

class defaultlist(list):    def __init__(self, fx):        self._fx = fx    def _fill(self, index):        while len(self) <= index:            self.append(self._fx())    def __setitem__(self, index, value):        self._fill(index)        list.__setitem__(self, index, value)    def __getitem__(self, index):        self._fill(index)        return list.__getitem__(self, index)


There is a python package available:

$ pip install defaultlist

Added indicies are filled with None by default.

>>> from defaultlist import defaultlist>>> l = defaultlist()>>> l[]>>> l[2] = "C">>> l[None, None, 'C']>>> l[4]>>> l[None, None, 'C', None, None]

Slices and negative indicies are supported likewise

>>> l[1:4][None, 'C', None]>>> l[-3]'C'

Simple factory functions can be created via lambda.

>>> l = defaultlist(lambda: 'empty')>>> l[2] = "C">>> l[4]'empty'>>> l['empty', 'empty', 'C', 'empty', 'empty']

It is also possible to implement advanced factory functions:

>>> def inc():...     inc.counter += 1...     return inc.counter>>> inc.counter = -1>>> l = defaultlist(inc)>>> l[2] = "C">>> l[0, 1, 'C']>>> l[4]4>>> l[0, 1, 'C', 3, 4]

See the Documentation for any further details.


One could implement a defaultlist that inherits from the MutableSequence abstract base class and wraps around the defaultdict. I do so in my coinflip package and expose it in the coinflip.collections submodule.

One would need to override the ABC like so:

class defaultlist(MutableSequence):    def __getitem__(self, i):        ...    def __setitem__(self, i, value):        ...    def __delitem__(self, i):        ...    def __len__(self):        ...            def insert(self):        ...

I would initialise this defaultlist by mirroring the defaultdict(default_factory=None) method, passing default_factory to an internal private defaultdict.

Like with c0fec0de's solution, I would recommend filling the indices with None by default (i.e. pass in a "none factory" method), otherwise you will get a KeyError using unaccessed indices.

The accessor methods (get, set and delete items) would have indices just be keys in the private defaultdict, and update that dictionary accordingly when items are added and/or removed.

There are lesser-used aspects of the builtin list which, if one wishes to emulate, need some special considerations. I wrote more in-depth about the subject here.