有關(guān)Python2.x版本下的dis模塊的使用
事情源于昨天看書看到一個(gè)有意思的部分舱污,就是在Python元組里面的元素如果存在可變的對象蒸痹,比如Python里面的列表,類似下面這種形式:
t = (1, 2, [3, 4])
那么如果我執(zhí)行t[2] += [5, 6]
會(huì)發(fā)生什么舞吭,首先給我的感覺是這個(gè)會(huì)報(bào)錯(cuò)吧幔虏,這個(gè)是顯而易見的,但是5能否添加進(jìn)去呢捂掰?哈哈敢会,突然覺得有點(diǎn)意思了,然后答案就是:
t變成(1, 2, [3, 4, 5, 6])
因?yàn)閠uple不支持對它的賦值这嚣,所以會(huì)拋出TypeError異常
具體的報(bào)錯(cuò)信息可以在交互式環(huán)境中自行測試一下
這個(gè)時(shí)候我們可以使用Python的dis模塊來反編譯一下鸥昏,看看操作的字節(jié)碼,如下所示:
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
因?yàn)槲沂褂玫氖荘ython2的版本姐帚,所以在使用dis.dis的時(shí)候吏垮,我們需要先將代碼編譯一下,即使用compile方法,這里需要注意的是第三個(gè)參數(shù)膳汪,第三個(gè)參數(shù)有三個(gè)選項(xiàng)唯蝶,"single"、"eval"遗嗽、"exec"粘我,具體的可以help查看一下,下面我們來說一下上面字節(jié)碼的關(guān)鍵行的解釋:
BINARY_SUBSCR 表示將t[2]存入棧頂TOS
INPLACE_ADD 表示計(jì)算 TOS+[5, 6]痹换,這一步是可以完成的征字,因?yàn)門OS指向的是一個(gè)可變對象,也就是[3, 4]這個(gè)列表
STORE_SUBSCR 這一步失敗娇豫,這是因?yàn)閠是一個(gè)元組匙姜,是不可變的,對其元素進(jìn)行賦值是不被允許的
所以我的建議是:
- 不要把可變對象放入元組里面
- 增量賦值不是一個(gè)原子操作锤躁,像上面的那樣搁料,雖然拋出錯(cuò)誤,但是還是完成了操作
- 了解Python代碼背后的運(yùn)行機(jī)制很有幫助
- 不建議這樣系羞,雖然我們可以使用t[2].extend([5, 6])來完成操作郭计,但是我們?nèi)匀徊唤ㄗh這樣做,不要將可變對象放入元組中椒振。