有關Python2.x版本下的dis模組的使用
事情源於昨天看書看到一個有意思的部分,就是在Python元組裡面的元素如果存在可變的物件,比如Python裡面的列表,類似下面這種形式:
t = (1, 2, [3, 4])
那麼如果我執行t[2] += [5, 6]
會發生什麼,首先給我的感覺是這個會報錯吧,這個是顯而易見的,但是5能否新增進去呢?哈哈,突然覺得有點意思了,然後答案就是:
t變成(1, 2, [3, 4, 5, 6])
因為tuple不支援對它的賦值,所以會丟擲TypeError異常
具體的報錯資訊可以在互動式環境中自行測試一下
這個時候我們可以使用Python的dis模組來反編譯一下,看看操作的位元組碼,如下所示:
In [14]: dis.dis(compile("t[2]+=[5, 6]", " ", "single"))
1 0 LOAD_NAME 0 (t)
3 LOAD_CONST 0 (2)
6 DUP_TOPX 2
9 BINARY_SUBSCR
10 LOAD_CONST 1 (5)
13 LOAD_CONST 2 (6)
16 BUILD_LIST 2
19 INPLACE_ADD
20 ROT_THREE
21 STORE_SUBSCR
22 LOAD_CONST 3 (None)
25 RETURN_VALUE
因為我使用的是Python2的版本,所以在使用dis.dis的時候,我們需要先將程式碼編譯一下,即使用compile方法,這裡需要注意的是第三個引數,第三個引數有三個選項,”single”、”eval”、”exec”,具體的可以help檢視一下,下面我們來說一下上面位元組碼的關鍵行的解釋:
BINARY_SUBSCR 表示將t[2]存入棧頂TOS
INPLACE_ADD 表示計算 TOS+[5, 6],這一步是可以完成的,因為TOS指向的是一個可變物件,也就是[3, 4]這個列表
STORE_SUBSCR 這一步失敗,這是因為t是一個元組,是不可變的,對其元素進行賦值是不被允許的
所以我的建議是:
- 不要把可變物件放入元組裡面
- 增量賦值不是一個原子操作,像上面的那樣,雖然丟擲錯誤,但是還是完成了操作
- 瞭解Python程式碼背後的執行機制很有幫助
- 不建議這樣,雖然我們可以使用t[2].extend([5, 6])來完成操作,但是我們仍然不建議這樣做,不要將可變物件放入元組中。