python 字節碼死磕


前言:

   如果你跟我一樣,對python的字節碼感興趣,想了解python的代碼在內存中到底是怎么去運行的,那么你可以繼續往下看,如果你是python新手,我建議你移步它處,本文適合有點基礎的python讀者。
   如果你不知道怎么生成python的字節碼文件,可以查閱我的 python 代碼反匯編  的博文  
 
 
python代碼的執行過程:
  1. python代碼編譯成字節碼【類似於匯編指令的中間語言】
  2. 字節碼由python虛擬機來執行編譯后的字節碼
 
說明:
          一個python語句會對 應若個字節碼指令,每個字節指令又對應着一個函數偏移量,可以理解為指令的ID
 
        虛擬機一條一條執行字節碼指令,從而完成程序的執行,而dis模塊可以對CPython代碼進行反匯編,生成字節碼指令
 
 
dis.dis() 轉化后的字節碼格式如下:
源碼行號  |  指令偏移量  | 指令符號 | 指令參數  |  實際參數值
       
說明: 不同版本的CPython 指令長度可能不同,但是 3.7的每條指令是2個字節,所以我們去看dis 生成的字節碼指令集的時候,指令偏移量總是從0開始,每增加一條在原來的偏移量上增加2
    故,指令偏移量的值,一般都是: 0 , 2 , 4, 6 , 8 , ... , 2n ( n>=0 )
 
變量指令解析

 
變量 — _const
 
LOAD_CONST :加載 const 變量,比如數值,字符串等等, 一般用於傳遞給函數作為參數
 
案例一:
test(2,'hello')

  

對應的字節碼指令
 
1             0 LOAD_NAME                0 (test)    
              2 LOAD_CONST               0 (2)
              4 LOAD_CONST               1 ('hello')
              6 CALL_FUNCTION            2            
              8 POP_TOP
             10 LOAD_CONST               2 (None)
             12 RETURN_VALUE

 

 
 
局部變量 — _FAST
 
LOAD_FAST :一般用於加載局部變量的值,也就是讀取值,用於計算或者函數調用傳傳等
STORE_FAST :一般用於保存值到局部變量
 
案例二:
 
n = n / p
 
對應的字節碼指令
1             0 LOAD_NAME                0 (n)
              2 LOAD_NAME                1 (p)
              4 BINARY_TRUE_DIVIDE
              6 STORE_NAME               0 (n)
              8 LOAD_CONST               0 (None)
             10 RETURN_VALUE

 

 
說明: 函數的形參也是局部變量,那么如何區分局部變量中的形參呢?
    形參是沒有初始化的,所以如果發現發現操作的一個局部變量只有 LOAD_FAST 而沒有 STORE_FAST,那么這個變量就是形參了。而其它的局部變量在使用之前肯定會使用STORE_FAST進行初始化。
 
案例三:
def test(arg1):
     num = 0
     print(num, arg1)
 
對應的字節碼指令
  1           0 LOAD_CONST               0 (<code object test at 0x10546c150, file "code.py", line 1>)
              2 LOAD_CONST               1 ('test')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (test)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE
 
Disassembly of <code object test at 0x10546c150, file "code.py", line 1>:
  2           0 LOAD_CONST               1 (0)
              2 STORE_FAST               1 (num)
 
  3           4 LOAD_GLOBAL              0 (print)
              6 LOAD_FAST                1 (num)
              8 LOAD_FAST                0 (arg1).  #只有LOAD_FAST ,沒有 STORE_FAST
             10 CALL_FUNCTION            2
             12 POP_TOP
             14 LOAD_CONST               0 (None)
             16 RETURN_VALUE

 

全局變量 — _GLOBAL
 
    LOAD_GLOBAL : 用來加載全局變量, 包括制定函數名,類名,模塊名等全局符號
    STORE_GLOBAL :用來給全局變量賦值
 
案例四
def test(arg1):
     global age
     age = 20
     print(age)

  

對應的字節碼指令
  1           0 LOAD_CONST               0 (<code object test at 0x1056e3150, file "code.py", line 1>)
              2 LOAD_CONST               1 ('test')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (test)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE
 
Disassembly of <code object test at 0x1056e3150, file "code.py", line 1>:
  3           0 LOAD_CONST               1 (20)
              2 STORE_GLOBAL             0 (age)
 
  4           4 LOAD_GLOBAL              1 (print)
              6 LOAD_GLOBAL              0 (age)
              8 CALL_FUNCTION            1
             10 POP_TOP
             12 LOAD_CONST               0 (None)
             14 RETURN_VALUE
 
常用數據類型

 
1.list
 
BUILD_LIST :  用於創建一個 list 結構
 
案例五
a = [1, 2]
 
對應的字節碼指令
  1           0 LOAD_CONST               0 (1)
              2 LOAD_CONST               1 (2)
              4 BUILD_LIST               2
              6 STORE_NAME               0 (a)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE                      //程序結束
 
案例六
[ x for x in range(4) if x > 2 ]
 
對應的字節碼
  1           0 LOAD_CONST               0 (<code object <listcomp> at 0x10bffa150, file "code.py", line 1>)
              2 LOAD_CONST               1 ('<listcomp>')
              4 MAKE_FUNCTION            0
              6 LOAD_NAME                0 (range)
              8 LOAD_CONST               2 (4)
             10 CALL_FUNCTION            1
             12 GET_ITER
             14 CALL_FUNCTION            1
             16 POP_TOP
             18 LOAD_CONST               3 (None)
             20 RETURN_VALUE
 
Disassembly of <code object <listcomp> at 0x10bffa150, file "code.py", line 1>:
  1           0 BUILD_LIST               0               //創建 list , 為賦值給某變量,這種時候一般都是語法糖結構了
              2 LOAD_FAST                0 (.0)        
        >>    4 FOR_ITER                16 (to 22)      //開啟迭代循環
              6 STORE_FAST               1 (x)          //局部變量x
              8 LOAD_FAST                1 (x)          // 導入 x
             10 LOAD_CONST               0 (2)          // 導入 2
             12 COMPARE_OP               4 (>)          // x 與 2 進行比較,比較符號為 >
             14 POP_JUMP_IF_FALSE        4              // 不滿足條件就跳過 “出棧“ 動作,既,continue" >>  4 FOR_ITER. “ 處
             16 LOAD_FAST                1 (x)          // 讀取滿足條件的局部變量x
             18 LIST_APPEND              2              // 把滿足條件的x 添加到list中
             20 JUMP_ABSOLUTE            4              
        >>   22 RETURN_VALUE                            //程序結束
 
 
2.dict
 
BUILD_MAP : 用於創建一個空的dict 
STORE_MAP : 用於初始化 dict 中的內容,賦值給變量
 
案例七
k = {'a': 1}
 
對應的字節碼
  1           0 LOAD_CONST               0 ('a')
              2 LOAD_CONST               1 (1)
              4 BUILD_MAP                1
              6 STORE_NAME               0 (k)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE
 
 
3.slice
 
BUILD_SLICE :        用於創建切片, 對於 list , tuple , 字符串都可以使用slice 的方式進行訪問
BINARY_SUBSCR : 讀取slice 的值
STORE_SUBSCR :   slice 的值賦值給變量。
 
案例八
num = [1, 2, 3]
a = num[1:2]
b = num[0:1:1]
num[1:2] = [10, 11]

  

對應的字節碼
  1           0 LOAD_CONST               0 (1)
              2 LOAD_CONST               1 (2)
              4 LOAD_CONST               2 (3)
              6 BUILD_LIST               3
              8 STORE_NAME               0 (num)
 
  2          10 LOAD_NAME                0 (num)
             12 LOAD_CONST               0 (1)
             14 LOAD_CONST               1 (2)
             16 BUILD_SLICE              2       #創建了一個切片
             18 BINARY_SUBSCR                 #讀取切片中的值
             20 STORE_NAME               1 (a)   #將讀取切片中的值賦值給變量 a
 
  3          22 LOAD_NAME                0 (num)
             24 LOAD_CONST               3 (0)
             26 LOAD_CONST               0 (1)
             28 LOAD_CONST               0 (1)
             30 BUILD_SLICE              3
             32 BINARY_SUBSCR
             34 STORE_NAME               2 (b)
 
  4          36 LOAD_CONST               4 (10)
             38 LOAD_CONST               5 (11)
             40 BUILD_LIST               2
             42 LOAD_NAME                0 (num)
             44 LOAD_CONST               0 (1)
             46 LOAD_CONST               1 (2)
             48 BUILD_SLICE              2
             50 STORE_SUBSCR
             52 LOAD_CONST               6 (None)
             54 RETURN_VALUE
 
 
4.循環
 
SETUP_LOOP :用於開始一個循環。 
JUMP_ABSOLUTE: 結束循環
 
案例九
i = 0
while i < 10:
    i += 1

  

對應的字節碼
  1           0 LOAD_CONST               0 (0)
              2 STORE_NAME               0 (i)
 
  2           4 SETUP_LOOP              20 (to 26)   // 循環開始處,26表示循環結束點
        >>    6 LOAD_NAME                0 (i)       // “>>" 表示循環切入點
              8 LOAD_CONST               1 (10)
             10 COMPARE_OP               0 (<)
             12 POP_JUMP_IF_FALSE       24
 
  3          14 LOAD_NAME                0 (i)
             16 LOAD_CONST               2 (1)
             18 INPLACE_ADD
             20 STORE_NAME               0 (i)
             22 JUMP_ABSOLUTE            6          // 邏輯上,循環在此處結束
        >>   24 POP_BLOCK                          
        >>   26 LOAD_CONST               3 (None)
             28 RETURN_VALUE 
 
案例十
num = 0
for i in range(5):
    num += i

 

對應的字節碼
  1           0 LOAD_CONST               0 (0)
              2 STORE_NAME               0 (num)
 
  2           4 SETUP_LOOP              24 (to 30)  //開始循環
              6 LOAD_NAME                1 (range)
              8 LOAD_CONST               1 (5)
             10 CALL_FUNCTION            1          //調用range 函數
             12 GET_ITER                            //獲取迭代 range 的 iter 
        >>   14 FOR_ITER                12 (to 28)  //開始進行 range 的迭代
             16 STORE_NAME               2 (i)
 
  3          18 LOAD_NAME                0 (num)
             20 LOAD_NAME                2 (i)
             22 INPLACE_ADD
             24 STORE_NAME               0 (num)
             26 JUMP_ABSOLUTE           14
        >>   28 POP_BLOCK
        >>   30 LOAD_CONST               2 (None)
             32 RETURN_VALUE
 
 
5.if
 
POP_JUMP_IF_FALSE : 條件結果為 FALSE  則跳出 目標的偏移指令
JUMP_FORWARD :       直接跳轉到目標便宜指令
COMPARE_OP:             比較指令
 
案例十一
num = 20
if num < 10:
    print('lt 10')
elif num > 10:
    print('gt 10')
else:
    print('eq 10')

對應的字節碼
  1           0 LOAD_CONST               0 (20)
              2 STORE_NAME               0 (num)
 
  2           4 LOAD_NAME                0 (num)
              6 LOAD_CONST               1 (10)
              8 COMPARE_OP               0 (<)
             10 POP_JUMP_IF_FALSE       22
 
  3          12 LOAD_NAME                1 (print)
             14 LOAD_CONST               2 ('lt 10')
             16 CALL_FUNCTION            1
             18 POP_TOP
             20 JUMP_FORWARD            26 (to 48)
 
  4     >>   22 LOAD_NAME                0 (num)
             24 LOAD_CONST               1 (10)
             26 COMPARE_OP               4 (>)
             28 POP_JUMP_IF_FALSE       40
 
  5          30 LOAD_NAME                1 (print)
             32 LOAD_CONST               3 ('gt 10')
             34 CALL_FUNCTION            1
             36 POP_TOP
             38 JUMP_FORWARD             8 (to 48)
 
  7     >>   40 LOAD_NAME                1 (print)
             42 LOAD_CONST               4 ('eq 10')
             44 CALL_FUNCTION            1
             46 POP_TOP
        >>   48 LOAD_CONST               5 (None)
             50 RETURN_VALUE 

 

參考資料:

  python 官方 dis介紹


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM