python關於+=的陷阱

Guuuuuu老師兒發表於2020-10-24

看下面程式碼

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

我們知道tuple元組是個不可變元素,所以更改元組的元素道理上是不行的,但是我改變的元素是個列表,它本身是可變的,這樣可行嗎??

先別去控制檯執行,猜是下面哪一種:

  1. t 變成 (1, 2, [30, 40, 50, 60])。
  2. 因為 tuple 不支援對它的元素賦值,所以會丟擲 TypeError 異常。
  3. 以上兩個都不是。
  4. a 和 b 都是對的。

\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\

\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
答案是第四種情況

我們使用Python Tutor(http://www.pythontutor.com)對執行程式碼進行視覺化
在這裡插入圖片描述在這裡插入圖片描述
最後我們看看背後的位元組碼是怎麼執行s[a] += b這種操作的
在這裡插入圖片描述到1是將 s[a] 的值存入 TOS(Top Of Stack,棧的頂端)
到2是計算 TOS += b。這一步能夠完成,是因為 TOS 指向的是一個可變物件
到3是s[a] = TOS 賦值。這一步失敗,是因為 s 是不可變的元組

所以才會出現即操作成功又報異常的現象

教訓:

  1. 不要把可變物件放在元組裡面
  2. 增量賦值不是一個原子操作(從位元組碼可以看出經過了若干步)

相關文章