1. 程式人生 > >python中的dis剖析原始碼及引數含義的講解

python中的dis剖析原始碼及引數含義的講解

Python 程式碼先被編譯為位元組碼後,再由Python虛擬機器來執行位元組碼, Python的位元組碼是一種類似彙編指令的中間語言, 一個Python語句會對應若干位元組碼指令,虛擬機器一條一條執行位元組碼指令, 從而完成程式執行。
Python dis 模組支援對Python程式碼進行反彙編, 生成位元組碼指令。
先來一小段程式碼:
  1. In[6]: def test():  
  2. ...         x = 1
  3. ...         if x < 3:  
  4. ...             return"yes"
  5. ...         else:  
  6. ...             return"no"
程式碼執行後會輸出:
  1. In[7]: import dis  
  2. In[8]: dis.dis(test)  
  3.   20 LOAD_CONST               1 (1)  
  4.               3 STORE_FAST               0 (x)  
  5.   36 LOAD_FAST                0 (x)  
  6.               9 LOAD_CONST               2 (3)  
  7.              12 COMPARE_OP               0 (<)  
  8.              15 POP_JUMP_IF_FALSE       
    22
  9.   418 LOAD_CONST               3 ('yes')  
  10.              21 RETURN_VALUE          
  11.   6     >>   22 LOAD_CONST               4 ('no')  
  12.              25 RETURN_VALUE          
  13.              26 LOAD_CONST               0 (None)  
  14.              29 RETURN_VALUE          

以第一條指令為例, 第一列的數字(2)表示對應原始碼的行數。第二列的數字是位元組碼的索引,指令LOAD_CONST在0位置。第三列是指令本身對應的人類可讀的名字。第四列表示指令的引數。第5列則是計算後的實際引數。其中的“>>" 表示跳轉的目標, 第4列的“22” 表明了跳轉到索引為22的指令。


Python程式碼在編譯過程中會生成CodeObject, CodeObject是在虛擬機器中的抽象表示, 在Python C原始碼中表示為PyCodeObject, 而生成的.pyc 檔案則是位元組碼在磁碟中的表現形式。以Python程式碼為講,test.__code__.co_code 表示test函式的位元組碼指令序列。
將此序列打印出來,
  1. code = [ord(i) for i in list(test.__code__.co_code)]  
  2. print code  
輸出:
  1. [1001012500124001002010700114220100308310040831000083]  
對照dis輸出的位元組碼指令, 以[100,1,0]序列為例。100表示在Python位元組碼定義中的索引,在python程式碼中,
 可以通過dis.opname[100]檢視,即為LOAD_CONST。而後的兩個位元組表示指令的引數。而dis輸出的位元組碼指令中,
第二列的位元組碼索引則是指當前指令在co_code序列中所在的位置。
dis輸出的位元組碼指令中,部分指令是沒有引數, 在co_code 中也同樣可以看到,83(RETURN_VALUE)直接接上下一條指令100(LOAD_CONST)。