每当数据发生变化时,如何子列表并触发事件?

NoB*_*own 12 python

list每当数据发生任何变化时,我都希望子类化并触发事件(数据检查).这是一个示例子类:

class MyList(list):

   def __init__(self, sequence):
        super().__init__(sequence)
        self._test()

    def __setitem__(self, key, value):
        super().__setitem__(key, value)
        self._test()

    def append(self, value):
        super().append(value)
        self._test()

    def _test(self):
        """ Some kind of check on the data. """
        if not self == sorted(self):
            raise ValueError("List not sorted.")
Run Code Online (Sandbox Code Playgroud)

在这里,我重写方法__init__,__setitem____append__检查数据是否发生变化.我认为这种方法是不可取的,所以我的问题是:如果底层数据结构发生任何类型的突变,是否有可能自动触发数据检查?

Geo*_*lly 7

正如你所说,这不是最好的方法.要正确实现此功能,您需要了解可以更改列表的每个方法.

要走的路是实现自己的列表(或者更确切地说是一个可变序列).执行此操作的最佳方法是使用您在collections.abc模块中找到的Python中的抽象基类.您必须只实现最少量的方法,模块会自动为您实现其余的方法.

对于您的具体示例,这将是这样的:

from collections.abc import MutableSequence

class MyList(MutableSequence):

    def __init__(self, iterable=()):
        self._list = list(iterable)

    def __getitem__(self, key):
        return self._list.__getitem__(key)

    def __setitem__(self, key, item):
        self._list.__setitem__(key, item)
        # trigger change handler

    def __delitem__(self, key):
        self._list.__delitem__(key)
        # trigger change handler

    def __len__(self):
        return self._list.__len__()

    def insert(self, index, item):
        self._list.insert(index, item)
        # trigger change handler
Run Code Online (Sandbox Code Playgroud)

性能

某些方法的默认实现速度很慢.例如__contains__,在Sequence类中定义如下:

def __contains__(self, value):
    for v in self:
        if v is value or v == value:
            return True
    return False
Run Code Online (Sandbox Code Playgroud)

根据您的课程,您可以更快地实现这一点.但是,性能通常不如编写易于理解的代码重要.它也可以使写一个类更难,因为你负责正确地实现方法.

  • @Dominik:我认为他的意思是如果省略一个方法,它将由`MutableSequence`提供,但它可能效率低于用C编写的本机列表方法.例如,abc提供的`clear`方法是大致相当于`while self:del self [-1]`.如果这恰好是瓶颈,你可以在`MyList`中自己实现更高效的版本. (2认同)
  • 例如,您可以将`clear`实现为`self._list.clear(); #触发更改处理程序`. (2认同)