说到python的增量赋值,你们里面就想到 +=, *= 之类的python
+=背后的特殊方法是 iadd 意思是:就地加法,若是一个类没有实现这个方法,那么python会退一步使用 add来进行相加code
a += b
若是a实现了就地相加方法,就是调用这个方法,同时对可变序列来讲,就是直接改动,就像调用a.extend(b)同样,可是若是a没有这个方法,那就执行 a = a + b, 总的来讲,可变序列通常都实现了就低价法,而不变序列根部就不支持这个操做,也不可能实现这个方法。对象
如今咱们得出的结论是:
可变序列能够增量赋值,不可变序列不能够增量赋值
这个结论到底对不对?咱们来看一个题:ip
t = (1,2,[3,4]) t[2] += [5,6]
用咱们刚才的结论来判断,由于t是个tuple,是不变序列,因此不支持增量赋值,因此这个确定会报错,没错,没错,咱们用刚才的结论成功的作出了这题,来看报错信息:input
<ipython-input-43-c823147bfbc0> in <module>() ----> 1 t[2] += [5,6] TypeError: 'tuple' object does not support item assignment
哈哈,很简单,接着,咱们再来看一下此时t的值:it
In [44]: t Out[44]: (1, 2, [3, 4, 5, 6])
你确定会打呼:what the f**k!!!!,什么鬼,怎么仍是变了,擦
结果: t被改动了,同时也抛出了错误class
来吧,咱们来看看这其中的原理
首先咱们看看python字节码对于s[a] += b这种类型的解析import
In [46]: import dis In [47]: dis.dis('s[a] += b') 1 0 LOAD_NAME 0 (s) 3 LOAD_NAME 1 (a) 6 DUP_TOP_TWO 7 BINARY_SUBSCR ------1 8 LOAD_NAME 2 (b) 11 INPLACE_ADD ---------2 12 ROT_THREE 13 STORE_SUBSCR ------------3 14 LOAD_CONST 0 (None) 17 RETURN_VALUE
三个步骤(对应代码里面的1,2,3):
1.将s[a]存入栈顶
2.完成s[a] += b
3.存贮结果module
有结果能够看出前两个步骤成功执行了,在最后一步报错,由于s是不可变的序列因此s[a] 赋值失败报错,经过这个例子咱们能够获得的结论以下:
1.尽可能不要把可变对象放到元组里面(经过extend方法能够避免这个问题)
2.增量赋值 操做不是原子操做,由于报错了,可是仍是完成了 += 操做
这个问题是个不常碰见的边界问题,不常见,可是了解一下仍是颇有用处的~原理