更改列表类型数据时为什么不调用__setitem__?

时间:2014-12-28 20:31:06

标签: python-2.7

在下面的示例中,如果数据是通过__setitem__设置的,则有一个具有= - 方法的类可以正常工作。但是,如果使用list方法隐式设置类型.append的数据,则不会调用__setitem__ - 方法。是否有某种方法可以确保在设置或修改数据时调用__setitem__(或类似“__moditem__”之类的东西)?

class MyClass(object):
    data = {}

    def __setitem__(self, key, value):
        self.data[key] = value
        print "I do not like change."

    def __getitem__(self, item):
        return self.data[item]


c = MyClass()
c['list'] = ['hello']   #does invoke setitem
c['list'].append('world')   #does not invoke __setitem__

处理这个问题的适当方法是什么?当然可以用

代替最后一行
c['list'] = c['list'] + ['world']

但是如果这个类在类库中,那么用户可能不知道。 :/

2 个答案:

答案 0 :(得分:2)

在改变容器本身时调用

__setitem__,而不是在改变包含的元素时调用。容器无法监控碰巧碰到的物品何时发生变化。毕竟考虑这段代码:

c = MyClass()
c['list'] = ['hello'] # Invokes setitem
foo = c['list'] # Grabs a reference to the object just put into the container
foo.append('world') # setitem is, of course, not invoked

如果您发现自己想要这样做,您可能希望容器保留(或至少返回),而不是标准列表类型和诸如此类的,但代理报告回中央数据存储区。 xml.etree模块就是这种事情的一个很好的例子。

答案 1 :(得分:1)

__setitem__仅通过以下语法调用:

obj[key] = value # this equals to obj.__setitem__(key, value)

在其他情况下,当您使用obj[key]时调用__getattr__

例如:

class MyClass(object):
    data = {}

    def __setitem__(self, key, value):
        self.data[key] = value
        print "__setitem__ called"

    def __getitem__(self, item):
        print "__getitem__ called"
        return self.data[item]


c = MyClass()
c['list'] = ['hello']   # __setitem__ called
c['list'].append('world')   # __getitem__ called

换句话说,在使用c ['list']的最后一行中,首先调用__getitem__并返回指向上面列表['hello']的初始化的指针。之后,调用此append方法。