扩展列表的正确方法

问题描述 投票:0回答:4

我想扩展“列表”类的功能并添加事件的自定义处理程序:“将新项目添加到列表”和“从列表中删除项目”。对于这个任务,我不想使用组合,继承更好。

我尝试过:

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']
# 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']

针对我的情况扩展课程“列表”的正确方法是什么?

python list inheritance
4个回答
7
投票

不要从

list
本身继承,而是从其抽象基类
collections.abc.MutableSequence
继承。这会为您完成所有基本工作,让您专注于想要更改的内容。这里有一个关于 ABC 的好问题:Why use Abstract Base Classes in Python?

例如:

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")

使用中(仍然不完全是你想要的,但更接近):

>>> 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'

3
投票

诸如

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

因为您无法控制内置类的实现方式,所以围绕内置类组合新类通常比从内置类继承更容易。


2
投票

如果您想覆盖 + 等运算符,则需要明确执行。 文档将帮助您找出需要更改的内容。


1
投票

看看 UserList 类:http://pydoc.org/2.2.3/UserList.html 它显示了您需要更改的所有方法。 问题是

type(ExtendedList([]) * 2) == list

© www.soinside.com 2019 - 2024. All rights reserved.