Reputation: 2917
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
Upvotes: 0
Views: 555
Reputation: 1121714
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))
Upvotes: 3