3

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 use composition, better is inheritence.

What 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 don'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']
# Don't out anythink; 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]
# Don't out anythink; collection now is: ['Four item']
collection *= 3
# Don't out anythink; collection now is: ['Four item', 'Four item', 'Four item']

What is right way to extend class "list" for my situation? Thanks for help.

eterey
  • 390
  • 1
  • 4
  • 16
  • 1
    It's not a good idea to define a subclass of list here. Instead, you should favor aggregation over inheritance – gefei Jan 17 '14 at 22:14
  • Each of these do different things, so use the one that is more appropriate for what you're trying to accomplish? – brandonscript Jan 17 '14 at 22:14
  • 1
    You've shown what happens, but what's wrong with it? What do you want to happen? – nmichaels Jan 17 '14 at 22:15
  • @nmichaels, I expect to get out on terminal "Added new item" when item added and "Item removed" when item removed on any case. But it's not work for "del collection[0:2]" and other list manipulation :( – eterey Jan 17 '14 at 22:16
  • 1
    Your question says "For this task i don't want use composition, better is inheritance." Why? That's not true for tasks like this in general. If there's something specific about your task that makes it true, knowing what that specific thing is would probably mean people could write better answers. (Or, if you're wrong, people could explain why composition and delegation still makes sense for your specific case.) – abarnert Jan 17 '14 at 22:27
  • @abarnert, no, it's not task specific. I just thought use inherits is more simple... But now I don't think so. – eterey Jan 17 '14 at 22:36
  • 1
    @uzumaxy: If you're coming to Python from another language, especially Java or another language that does OO old-C++-style, this is one of those things that's very surprising. Without duck typing, inheritance is the one and only way to create objects that act like instances of another type. With duck typing, it's only one way, and often not the best one. – abarnert Jan 17 '14 at 23:08

4 Answers4

6

Rather than inherit from list itself, inherit from its Abstract Base Class, collections.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.

Community
  • 1
  • 1
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
3

Operations such as *=, +=, and del are implemented using the list class's operator functions like __add__, __delitem__, __delslice__, etc. There are lots of them. If you want to intercept every possible call to your "extended" list class, you'll need to override most if not all of those operators.

Because you don't have control over how the builtin classes are implemented, it's usually easier to compose a new class around a builtin than to inherit from a builtin.

dg99
  • 5,456
  • 3
  • 37
  • 49
  • Seems, I am wrong and really better to use aggregation or to inherit from MutableSequence... – eterey Jan 17 '14 at 22:30
2

If you want to override operators like +, you'll need to do it explicitly. The documentation will help you figure out what needs to change.

nmichaels
  • 49,466
  • 12
  • 107
  • 135
1

Have a look at the class UserList: http://pydoc.org/2.2.3/UserList.html It shows all methods you need to change. A problem is that type(ExtendedList([]) * 2) == list.

User
  • 14,131
  • 2
  • 40
  • 59
  • 1
    This is a really obsolete answer. Python 2.2+ has no problem extending `list`, that "problem" has had a solution since 2.3, and 2.6+ has the [`MutableSequence`](http://docs.python.org/2/library/collections.html#collections-abstract-base-classes) ABC, removing the last reason for anyone to ever look at `UserList` again, which is why it was deprecated and removed from the docs entirely. – abarnert Jan 17 '14 at 22:26
  • Right. It is obsolete now. just could not remember MutableSequence. – User Jan 17 '14 at 22:29
  • Sorry, it was removed in 3.0, not 2.6. 2.6 crams it and [the other related obsolete modules](http://docs.python.org/2.6/library/userdict.html?highlight=userlist#module-UserList) into a single page that reminds you every few sentences that "Note: This module is available for backward compatibility only." Still, it's not a good suggestion. Especially for an OP who looks like he's using Python 3.x. – abarnert Jan 17 '14 at 22:33