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__
对其进行修改。我在这里误解了什么?我经常在使用词典时遇到这个问题。
值得指出的是self.__data
中的值已定义__iadd__
,但未定义__add__
,如果可能,我更倾向于修改值。我还想避免创建__setitem__
方法。
以下是一个展示问题的测试用例,我已将上面的代码留给现有答案。
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]
答案 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__()
方法。