替换Python列表对象的特殊方法

2 投票
1 回答
557 浏览
提问于 2025-04-16 17:40

我想写一个类,这个类是Python列表的子类,并且在列表发生变化时能通知另一个对象。因为有很多方法需要重写,所以我选择了这样的解决方案,而不是重写所有会改变列表的方法:

destructiveMethods = ["__setitem__",
                      "__setslice__",
                      "__delitem__",
                      "__delslice__",
                      "append",
                      "extend",
                      "remove",
                      "reverse",
                      "sort"]

class OwnedList(list):
    def __init__(self, owner, initValue=[]):
        super(OwnedList, self).__init__(initValue)


        def wrappedMethod(method):
            def resultMethod(*args, **kwargs):
                ret = method(*args, **kwargs)
                self.owner.notify()
                return ret
            return resultMethod

        self.owner = owner
        for m in destructiveMethods:
            setattr(self, m, wrappedMethod(getattr(self, m)))

这个方法对像“append”这样的普通方法有效,但对于一些特殊方法,比如“__setitem__”,我就直接使用旧的方法了。

我注意到,如果我打印“append”的值,我得到的是类似这样的内容:

<built-in method append of list object at 0x267a7a0>

但是对于“__setitem__”(在普通列表上),我得到的是:

<method-wrapper '__setitem__' of list object at 0x266fd40>

也许这和我的问题有关。

任何帮助都很感激。如果你知道更好的方法来实现我需要做的事情,请分享你的想法。谢谢。

更新: 我还注意到,直接在OwnedList对象上调用“__setitem__”是按预期工作的,但使用方括号就不行。

1 个回答

2

特殊方法只能在对象的类型上定义,而不能在具体的实例上定义来源

比较一下

>>> class A(object):
...     __getitem__ = lambda self,i: 42
>>> A()[0]
42

>>> class B(object):
...     def __init__(self):
...             self.__getitem__ = lambda self,i: 42
>>> B()[0]
TypeError: 'B' object does not support indexing

你应该调整一下 A,也就是说,要直接在类的主体中定义你的特殊方法,而不是在构造函数里。

撰写回答