Question

How can every set method in python's list object be overridden in a derived object such that every item in that list is of a specific class?

Consider

class Index(int):
    pass


class IndexList(list):

    def __init__(self, int_list):
        for el in int_list:
            self.append(Index(el))

    def __setitem__(self, key, val):
        super(IndexList, self).__setitem__(key, Index(val))

    # override append insert etc...

Can this be done without directly overriding every single function that adds elements to the list? I expected simply overriding __setitem__ was enough.

Example, if append is not overridden.

ilist = IndexList([1,2])
ilist.append(3)

for i in ilist:
    print(isinstance(i, Index)) # True, True, False
Was it helpful?

Solution

You'll have to implement the various directly; the underlying C implementation does not call __setitem__ for each and every change, as it is far more efficient to directly manipulate the (dynamically grown) C array.

Take a look at the collections abstract base classes, specifically at the MutableSequence ABC, to get an idea of what methods all can mutate your list, to maintain your type invariant you'd need to implement insert, append, extend and __iadd__.

Better still, you can use the collections.MutableSequence() class as an alternative base class to list; this is a pure-python implementation that does cast many of those methods as calls to a core set of methods; you'd only need to provide implementations for __len__, __getitem__, __setitem__, __delitem__ and insert; any method named in the Abstract Methods column of the table.

class IndexList(collections.MutableSequence):
    def __init__(self, int_list):
        self._list = []
        for el in int_list:
            self.append(Index(el))

    def __len__(self): return len(self._list)
    def __getitem__(self, item): return self._list[item]
    def __delitem__(self, item): del self._list[item]

    def __setitem__(self, index, value):
        self._list.key[index] = Index(value)

    def insert(self, index, value):
        self._list.insert(index, Index(value))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top