Python:扩展列表的正确方式

3
我希望扩展“list”类的功能,并添加自定义事件处理程序:“向列表中添加新项目”和“从列表中删除项目”。对于此任务,我不想使用组合,继承更好。
我尝试的方法是:
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')

但是它不能正常工作。我无法捕获所有的添加和删除事件。例如:
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']

什么是扩展“list”类的正确方式?谢谢帮助。

1
在这里定义一个列表的子类并不是一个好主意。相反,你应该优先选择聚合而非继承。 - gefei
1
你已经展示了发生了什么,但是有什么问题吗?你想要发生什么? - nmichaels
@nmichaels,我期望在任何情况下添加新项时在终端上得到“已添加新项”的输出,并在删除项时得到“已删除项”的输出。但是对于“del collection [0:2]”和其他列表操作,它并不起作用:( - eterey
1
你的问题说:“对于这个任务,我不想使用组合,继承更好。”为什么?一般来说,这并不是真的。如果有关于你的任务使得这个说法成立的具体原因,了解这些原因可能会让人们能够写出更好的答案。(或者,如果你错了,人们可以解释为什么组合和委托仍然适用于你的特定情况。) - abarnert
1
如果你是从其他编程语言,尤其是Java或者老式C++的面向对象编程方式转到Python的话,这个问题可能会让你感到非常惊讶。在没有鸭子类型的情况下,继承是创建像另一个类型实例一样的对象的唯一方法。而有了鸭子类型,继承只是其中的一种方式,而且通常不是最好的方式。 - abarnert
显示剩余3条评论
4个回答

6
不要直接继承自list,而是继承自它的抽象基类:collections.MutableSequence。这样做可以为你完成所有基本工作,让你专注于想要更改的内容。有一个关于ABC的好问题在这里

3

*=, +=, 和 del 这样的操作是使用list类的运算符函数实现的,例如__add__, __delitem__, __delslice__等等。 它们有很多。 如果您想拦截对“扩展”列表类的每个可能的调用,您将需要覆盖大多数甚至所有这些运算符。

由于您无法控制内置类的实现方式,因此通常更容易在内置类周围构建一个新类而不是继承自内置类。


似乎我错了,最好使用聚合或从MutableSequence继承... - eterey

2
如果想要覆盖像 + 这样的运算符,你需要显式地这么做。《官方文档》可以帮助你弄清楚需要修改什么。

1

1
这是一个非常过时的答案。Python 2.2+没有扩展list的问题,这个“问题”自2.3以来就有了解决方案,而2.6+具有MutableSequence ABC,消除了任何人再次查看UserList的最后一个原因,这就是为什么它被弃用并从文档中完全删除的原因。 - abarnert
没错,它现在已经过时了。我只是想不起来MutableSequence。 - User
抱歉,它在3.0中被删除了,而不是2.6。2.6将其和其他相关的过时模块压缩到一个页面中,每隔几个句子提醒你“注意:此模块仅供向后兼容使用。”但这仍然不是一个好建议。特别是对于看起来正在使用Python 3.x的OP。 - abarnert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接