1. 程式人生 > >記錄一個python裡面很神奇的操作,對一個包含列表的元組進行增量賦值,成功賦值但還報錯

記錄一個python裡面很神奇的操作,對一個包含列表的元組進行增量賦值,成功賦值但還報錯

記錄一個python裡面很神奇的操作

今天記錄一個很神奇的操作。關於序列的增量賦值。如果你很熟悉增量賦值,你也不妨看下去,我想說的是有關於增量賦值和元組之間一種神奇的操作。來自 《流暢的Python》 一書,讓我們更加深入地瞭解裡面的原理

神奇的操作

>>>t = (1,2,[30,40])
>>>t[2] += [50,60]

上面這段程式碼會出現什麼樣的情況
a. t會變成(1,2,[30,40,50,60])
b. 因為tuple不支援對它的元素賦值,所以會丟擲TypeError異常
c. 以上兩個都不是
d. a和b都是對的
大多數人都會認為b是正確的,本書的作者也是這麼認為的,但是實際上呢?卻是選 b

不要疑惑,就是這樣,既報錯,又成功進行了修改

首先講一下增量賦值

我們使用增量賦值運算子 +=*= 等增量賦值運算子的時候(用 += 舉例),使用的是背後的特殊方法 __iadd__,如果沒有實現這個方法則會退而求其次,使用 __add__ .

兩者的區別是什麼?
用列表舉例 a+=b,使用 __add__ 的話就像是使用了a.extend(b),如果使用 __add__ 的話,則是 a = a+b,前者是直接在原列表上進行擴充套件,而後者是先從原列表中取出值,在一個新的列表中進行擴充套件,然後再將新的列表物件返回給變數,顯然後者的消耗要大些。

繼續將那個神奇的操作

既然我們瞭解了變數賦值,那麼我們就可以更深入一些了。

t[2] += [50,60] 實現原理:
1. 將t[2]的值,存入TOS(Top Of Stack 棧的頂端)。
2. 計算TOS +=b 。這一步可以完成,是因為TOS指向的是一個列表(可變物件)。
3. t[2] = TOS 賦值。這一步失敗,並且報錯,因為t是不可變的元組

我們可以通過python tutor這個網站去找到裡面執行的詳細過程
image
image