Sometimes, things are easier without inheriting from builtin objects...:
from collections import MutableSequence, Iterable
class MyList(MutableSequence):
def __init__(self, type, iterable=()):
self._data = []
self._type = type
self.extend(iterable)
def insert(self, index, item):
if not isinstance(item, self._type):
raise TypeError
self._data.insert(index, item)
def __len__(self):
return len(self._data)
def __getitem__(self, *args):
return self._data.__getitem__(*args)
def __delitem__(self, *args):
self._data.__delitem__(*args)
def __setitem__(self, key, value):
if isinstance(value, collections.Iterable) and isinstance(key, slice):
values = []
for val in value:
if not isinstance(value, self._type):
raise TypeError
else:
if not isinstance(value, self._type):
raise TypeError
self._data[k] = value
Note, I haven't gone into any discussion about whether this is a good idea. Some people will tell you not to do this because python is built on "duck-typing". Others say that isinstance
is perfectly fine to use -- provided that you do so responsibly. One proponent of this view (Alex Martelli) is generally regarded as a python expert. He recommends isinstance
checking against abstract base classes and calls this practice "goose-typing". This practice seems to have gained some traction as the standard library is slowly adding support that would allow more robust run-time checking of these things -- Consider PEP-0484 (type hinting).
I suppose, my point is that if you use this class, don't do:
lst1 = MyList(list)
lst2 = MyList(int)
Do something like:
lst1 = MyList(collections.MutableSequence)
lst2 = MyList(numbers.Integral)