意外的对象分配

时间:2010-02-09 17:16:50

标签: python variable-assignment dictionary

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

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

  File "nethogs2.py", line 130, in __iadd__
    self[epoch] += traffic
TypeError: 'TrafficData' object does not support item assignment

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

在我看来,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]

3 个答案:

答案 0 :(得分:6)

你到底在做什么:

self[epoch] += traffic

是:

self[epoch] = self[epoch] + traffic

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

您还需要:

def __setitem__(self, epoch, value):
        self.__data[epoch] = value

或类似的东西。

答案 1 :(得分:1)

  

值得指出的是   self.__data中的值有   __iadd__已定义,但不是__add__,我更倾向于修改其中的值   如果可能的话。

为了向以前的答案添加一些精确度,在您描述的情况下,self[epoch] += traffic完全转换为:

self[epoch] = self[epoch].__iadd__(traffic)

因此,如果你想要的只是__iadd__的副作用,没有项目分配部分,你的选择仅限于你已经在你发布的代码的评论中确定的变通方法,或者自己致电__iadd__ - 可能通过operator模块,但我相信operator.__iadd__(self[epoch], traffic)与更简单的self[epoch].__iadd__(traffic)相比没有任何附加价值(self[epoch] __iadd__方法。

答案 2 :(得分:0)

代码:

self[epoch] += traffic

是语法糖:

self[epoch] = self[epoch] + traffic

所以分配不出意外是+= 中的作业。因此,您还需要覆盖__setitem__()方法。