意外的对象分配

Mat*_*ner 0 python dictionary variable-assignment

class TrafficData(object):
    def __init__(self):
        self.__data = {}
    def __getitem__(self, epoch):
        if not isinstance(epoch, int):
            raise TypeError()
        return self.__data.setdefault(epoch, ProcessTraffic())
    def __iadd__(self, other):
        for epoch, traffic in other.iteritems():

            # these work
            #existing = self[epoch]
            #existing += traffic

            # this does not
            self[epoch] += traffic # here the exception is thrown

        return self
Run Code Online (Sandbox Code Playgroud)

在上面修剪过的代码中,我不期望一个项目分配,但显然在标记的行上发生了一个,并抛出以下异常:

  File "nethogs2.py", line 130, in __iadd__
    self[epoch] += traffic
TypeError: 'TrafficData' object does not support item assignment
Run Code Online (Sandbox Code Playgroud)

但是,如果我改为使用前面两条注释掉的行,则不会抛出任何异常.

在我看来,2应该以相同的方式表现.self[epoch]返回对对象的引用,并通过该对象对其进行修改__iadd__.我在这里误解了什么?我经常在使用词典时遇到这个问题.

Update0

值得指出的是,self.__data已经__iadd__定义了值,但没有定义,__add__如果可能的话,我更倾向于修改值.我还想避免创建一个__setitem__方法.

UPDATE1

下面是一个演示问题的测试用例,我已经将上面的代码留给了现有的答案.

class Value(object):
    def __init__(self, initial=0):
        self.a = initial
    def __iadd__(self, other):
        self.a += other
        return self
    def __str__(self):
        return str(self.a)

class Blah(object):
    def __init__(self):
        self.__data = {}
    def __getitem__(self, key):
        return self.__data.setdefault(key, Value())

a = Blah()
b = a[1]
b += 1
print a[1]
a[1] += 2
print a[1]
Run Code Online (Sandbox Code Playgroud)

gru*_*czy 6

你到底在做什么:

self[epoch] += traffic
Run Code Online (Sandbox Code Playgroud)

是:

self[epoch] = self[epoch] + traffic
Run Code Online (Sandbox Code Playgroud)

但是你没有定义__setitem__方法,所以你可以自己做.

你还需要:

def __setitem__(self, epoch, value):
        self.__data[epoch] = value
Run Code Online (Sandbox Code Playgroud)

或类似的东西.