增量赋值运算符 +=和*= 一般作用于可变序列上
如果对于不可变序列(如tuple), 每次都会生成一个新的对象,效率就很低。
+= 对应的方法__iadd__就地加法。如果一个类没有实现,python会退一步调用__add__
a +=b
以上实例中,如果a实现了__iadd__方法,对于可变序列(list、bytearray、array.array)来说,a会就地改动,等于调用了a.extend(b)。
如果没有实现__iadd__就是等于a = a+b 先计算a+b等到一个新的对象,赋值给a
*= 对应的方法__imul__,原理同上
一个+=的谜题
以下是2013 python巴西会议中,有人提出这个谜题
>>> t = (1,2,[20,30])
>>> t[2] += [40, 50]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [20, 30, 40, 50])
以上代码看出来,t[2]被改动了,但是也有异常抛出,因为t是元祖,不支持对他的元素赋值。
如果分析字节码,可以得出以下步骤,解析了以上现象:
- t[2]的值存入TOS(TOP Of Stack 栈的顶端)
- 计算TOS +=[40, 50],这一步可以完成没有报错,因为TOS是指向的一个可变对象 列表
- t[2] = TOS 赋值操作,这里就会报错,因为t是不可变的元祖,
以上操作的教训:
- 不要把可变对象放到元祖中。
- 增量赋值不是原子操作,虽然抛出了异常,但是还是完成增量操作