說到python的增量賦值诽偷,大家里面就想到 +=侥祭, *= 之類的
+=背后的特殊方法是 iadd 意思是:就地加法韩容,如果一個(gè)類沒有實(shí)現(xiàn)這個(gè)方法,那么python會(huì)退一步使用 add來進(jìn)行相加
a += b
如果a實(shí)現(xiàn)了就地相加方法诸老,就是調(diào)用這個(gè)方法,同時(shí)對(duì)可變序列來說钳恕,就是直接改動(dòng)别伏,就像調(diào)用a.extend(b)一樣,但是如果a沒有這個(gè)方法忧额,那就執(zhí)行 a = a + b, 總的來說厘肮,可變序列一般都實(shí)現(xiàn)了就低價(jià)法,而不變序列根部就不支持這個(gè)操作宙址,也不可能實(shí)現(xiàn)這個(gè)方法轴脐。
現(xiàn)在我們得出的結(jié)論是:
可變序列可以增量賦值,不可變序列不可以增量賦值
這個(gè)結(jié)論到底對(duì)不對(duì)抡砂?我們來看一個(gè)題:
t = (1,2,[3,4])
t[2] += [5,6]
用我們剛才的結(jié)論來判斷大咱,因?yàn)閠是個(gè)tuple,是不變序列注益,所以不支持增量賦值碴巾,所以這個(gè)肯定會(huì)報(bào)錯(cuò),沒錯(cuò)丑搔,沒錯(cuò)厦瓢,我們用剛才的結(jié)論成功的做出了這題,來看報(bào)錯(cuò)信息:
<ipython-input-43-c823147bfbc0> in <module>()
----> 1 t[2] += [5,6]
TypeError: 'tuple' object does not support item assignment
哈哈提揍,很簡(jiǎn)單,接著煮仇,我們?cè)賮砜匆幌麓藭r(shí)t的值:
In [44]: t
Out[44]: (1, 2, [3, 4, 5, 6])
你肯定會(huì)打呼:what the f**k!!!!劳跃,什么鬼,怎么還是變了浙垫,擦
結(jié)果: t被改動(dòng)了刨仑,同時(shí)也拋出了錯(cuò)誤
來吧,我們來看看這其中的原理
首先我們看看python字節(jié)碼對(duì)于s[a] += b這種類型的解析
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
三個(gè)步驟(對(duì)應(yīng)代碼里面的1夹姥,2杉武,3):
1.將s[a]存入棧頂
2.完成s[a] += b
3.存貯結(jié)果
有結(jié)果可以看出前兩個(gè)步驟成功執(zhí)行了,在最后一步報(bào)錯(cuò)辙售,因?yàn)閟是不可變的序列所以s[a] 賦值失敗報(bào)錯(cuò)轻抱,通過這個(gè)例子我們可以得到的結(jié)論如下:
1.盡量不要把可變對(duì)象放到元組里面(通過extend方法可以避免這個(gè)問題)
2.增量賦值 操作不是原子操作,因?yàn)閳?bào)錯(cuò)了旦部,但是還是完成了 += 操作
這個(gè)問題是個(gè)不常遇見的邊界問題祈搜,不常見,但是了解一下還是很有用處的~