如何检测 Python class 中列表的变化,或者为什么 "setter" 不触发

How to detect changes of a list whithin a Python class, or why does "setter" not trigger

我想在 Python class 中有一个列表。每当列表中的元素发生更改时,我都需要 运行 一些逻辑。我对 python 中的 classes 还很陌生,我对 setter 的处理方法可能非常幼稚。这对我来说很直观:

class test():
    def __init__(self):
        self._R = [False]*16

    @property
    def R(self):
        return self._R

    @R.setter
    def R(self,a):
        print('Why do I not get reached?')
        self._R = a

W = test()
W.R[0] = True

但是 setter 永远不会被触发。如果你能在正确的方向给我一个缺口,我会非常饱满。

我尝试根据@user2357112supportsMonica 的评论编写代码:

class test():
    def __init__(self):
        self.A = 1

    def foo(self):
        print(self.A)

    class R_Class():
        def __init__(self):
            self._R = [False]*16

        def __setitem__(self,index,value):
            self._R[index] = value
            test.foo() #Here I need to call foo somehow
        def __getitem__(self,index):
            return self._R[index]
    R = R_Class()


W = test()
W.R[0] = True


但是这种方法会导致另一个问题,有没有办法从 sub class 中正确调用 foo 函数?

您可以创建一个新的类似列表的 class,它接受一个回调函数并在列表更改时执行它:

class CallbackList:  # PEP-8 style suggests UpperCase class names
    def __init__(self, callback=None):
        self._list = [False]
        self._callback = callback  # Python functions are first-class objects just like ints, strings, etc, so this is completely legal

    def __setitem__(self, index, value):
        self._list[index] = value
        if self._callback:
            self._callback()  # Executes the callback function whenever a value is set

    def __getitem__(self, index):
        return self._list[index]


class Test:
    def __init__(self):
        self.callback_list = CallbackList(callback=self.foo)

    def foo(self):
        print("You changed the list!")


W = Test()
W.callback_list[0] = True  # This prints "You changed the list!"

请注意,这仍然无法捕获所有可能的更改。例如:

W = Test()
some_list = [1, 2, 3]

W.callback_list[0] = some_list  # This triggers the callback function
print(W.callback_list[0])  # [1, 2, 3]

some_list.append(4)  # This does NOT trigger the callback function!
print(W.callback_list[0])  # [1, 2, 3, 4] !