I want to extend functionality of class "list" and add custom handlers for events: "Add new item to list" and "Remove item from list". For this task I don't want to use composition, inheritance is better.
I tried do:
class ExtendedList(list):
def append(self, obj):
super(ExtendedList, self).append(obj)
print('Added new item')
def extend(self, collection):
if (hasattr(collection, '__iter__') or hasattr(collection, '__getitem__')) and len(collection)>0:
for item in collection:
self.append(item)
def insert(self, index, obj):
super(ExtendedList, self).insert(index, obj)
print('Added new item')
def remove(self, value):
super(ExtendedList, self).remove(value)
print('Item removed')
but it doesn't work correctly. I can't catch all adding and removing events. For example:
collection = ExtendedList()
collection.append('First item')
# Out: "Added new item\n"; collection now is: ['First item']
collection.extend(['Second item', 'Third item'])
# Out: "Added new item\nAdded new item\n"; collection now is: ['First item', 'Second item', 'Third item']
collection += ['Four item']
# Doesn't output anything; collection now is: ['First item', 'Second item', 'Third item', 'Four item']
collection.remove('First item')
# Out: "Item removed\n"; collection now is: ['Second item', 'Third item', 'Four item']
del collection[0:2]
# Doesn't output anything; collection now is: ['Four item']
collection *= 3
# Doesn't output anything; collection now is: ['Four item', 'Four item', 'Four item']
What is the right way to extend class "list" for my situation?
Rather than inherit from list
itself, inherit from its Abstract Base Class, collections.abc.MutableSequence
. This does all of the basic work for you, letting you focus on what you want to change. There is a good question on ABCs here: Why use Abstract Base Classes in Python?
For example:
from collections.abc import MutableSequence
class ExtendedList(MutableSequence):
def __init__(self, logger=print):
self._content = []
self._logger = logger
def __getitem__(self, index):
return self._content[index]
def __setitem__(self, index, item):
self._content[index] = item
def __delitem__(self, index):
del self._content[index]
self._logger("item removed")
def __len__(self):
return len(self._content)
def insert(self, index, item):
self._content.insert(index, item)
self._logger("item added")
In use (still not quite what you want, but closer):
>>> collection = ExtendedList()
>>> collection.append("First item")
item added
>>> collection.extend(["Second item", "third item"])
item added
item added
>>> collection += ["Fourth item"]
item added
>>> collection.remove("First item")
item removed
>>> del collection[0:2]
item removed
>>> collection *= 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for *=: 'ExtendedList' and 'int'