首頁  >  文章  >  後端開發  >  Python虛擬機器字節碼之控制流怎麼實現

Python虛擬機器字節碼之控制流怎麼實現

王林
王林轉載
2023-05-26 12:13:201566瀏覽

控制流程實作

控制流程這部分程式碼主要涉及下面幾條字節碼指令,下面的所有字節碼指令都會有一個參數:

  • JUMP_FORWARD,指令完整條指令會將目前執行字節碼指令的位置加上這個參數,然後跳到對應的結果繼續執行。

  • 如果堆疊頂部元素為true,則改變位元組碼執行位置為接收的參數值的指令為「POP_JUMP_IF_TRUE」。將棧頂元素彈出。

  • POP_JUMP_IF_FALSE,這條指令和 POP_JUMP_IF_TRUE 一樣,唯一差異就是判斷堆疊頂元素是否等於 true。

  • JUMP_IF_TRUE_OR_POP,如果堆疊頂部元素等於等於 true 則將字節碼執行位置設定成參數對應的值,且不需要將堆疊頂元素彈出。如果棧頂元素為 false,就必須彈出該元素。

  • JUMP_IF_FALSE_OR_POP,和JUMP_IF_TRUE_OR_POP一樣只不過需要堆疊頂元素等於 false 。

  • JUMP_ABSOLUTE,直接將位元組碼的執行位置設定成參數的值。

總的來說,這些跳轉指令可以讓Python 的解釋器在執行字節碼時根據特定條件來改變執行流程,實現循環、條件語句等基本語言結構。

現在我們使用一個範例來深入理解上面的各種指令的執行過程。

import dis
 
 
def test_control01():
    a = 1
 
    if a > 1:
        print("a > 1")
    elif a < 1:
        print("a < 1")
    else:
        print("a == 1")
 
if __name__ == &#39;__main__&#39;:
    dis.dis(test_control01)

上面的程式輸出結果如下:

  6           0 LOAD_CONST                  0 (a)
 
  8           4 LOAD_FAST 0 (a)
              6 LOAD_CONST               1 (1)
                  10 POP_JUMP_IF_FALSE       22
 
  9          12 LOAD_GLALAL)   14 LOAD_CONST               2 (' a > 1')
             16 CALL_FUNCTION            1
                  26 (to 48)
 
 10     >>   22 LOAD_FAST                       1 (1)
             26 COMPARE_OP               0 (                30 LOAD_GLOBAL              0 (print)
             32 LOAD_CONST           32 LOAD_CONST     34 CALL_FUNCTION            1
             36 POP_TOP
            38 JUMP_#       3     >>   40 LOAD_GLOBAL              0 (print)
             42 LOAD_CONST            42 LOAD_CONST   1  #             44 CALL_FUNCTION            1
             46 POP_TOP##             0 (None)
             50 RETURN_VALUE


我們現在來模擬一下上面的位元組碼執行過程,我們使用counter 表示目前字節碼的執行位置:

在字節碼還沒開始執行之前,堆疊空間和counter 的狀態如下:



現在執行第一條字節碼LOAD_CONST,執行完之後counter = 2,因為這條字節碼佔一個字節,參數堆疊一個字節,因此下次執行的字節碼的位置在bytecode 的低三個位置,對應的下標為2,因此counter = 2 。

Python虛擬機器字節碼之控制流怎麼實現

現在執行第二個字節碼STORE_FAST,讓a 指向1 ,同樣的STORE_FAST 操作碼和操作數各佔一個字節,因此執行完這條字節碼之後堆疊空間沒有數據,counter = 4 。

Python虛擬機器字節碼之控制流怎麼實現

接下來LOAD_FAST 將a 指向的物件也就是1 載入進入堆疊中,此時的counter = 6,LOAD_CONST 將常數1 載入進行入堆疊空間當中,此時counter = 8,執行完這兩條指令之後,堆疊空間的變化如下圖所示:

Python虛擬機器字節碼之控制流怎麼實現

接下來的一條指令是COMPARE_OP ,這個指令有一個參數表示比較的符號,這裡是比較a > 1,並且會將比較的結果壓入棧中,比較的結果是false ,因為COMPARE_OP 首先會將棧空間的兩個輸入彈出,因此在執行完這條指令之後堆疊空間和counter 的值如下:

Python虛擬機器字節碼之控制流怎麼實現

下面一條指令為POP_JUMP_IF_FALSE,根據前面的字節碼意義,這個字節碼會將棧頂的false 彈出,並且會進行跳轉,並且將counter 的值直接編程參數的值,這裡他的參數是22 ,因此counter = 22,在執行完這條指令之後,結果如下:

Python虛擬機器字節碼之控制流怎麼實現

因為現在已經跳到了22 ,因此接下來執行的指令為LOAD_FAST,將變數a 載入進入堆疊空間,LOAD_CONST 將常數1 載入進入堆疊空間,在執行完這兩條執行後,變化情況如下:

Python虛擬機器字節碼之控制流怎麼實現

在次執行POP_JUMP_IF_FALSE,這回的結果也是false ,因此繼續執行POP_JUMP_IF_FALSE,這次的參數是40,直接將counter 的值設為40 。

Python虛擬機器字節碼之控制流怎麼實現

接下來LOAD_GLOBAL 載入一個全域變數print 函數counter 變成42 ,LOAD_CONST 載入字串"a == 1" 進入堆疊空間,counter = 44,此時狀態如下:

Python虛擬機器字節碼之控制流怎麼實現

CALL_FUNCTION 這個字節碼有一個參數,表示呼叫函數的參數的個數,這裡是1,因為print 函數只有一個參數,然後輸出字串"a== 1",但這裡要注意的是print 函數會回傳一個None,因此執行完CALL_FUNCTION 之後狀態如下:

Python虛擬機器字節碼之控制流怎麼實現

至此差不多上面的函數差不多執行完了,後面幾條字節碼很簡單,就不再進行敘述了。

以上是Python虛擬機器字節碼之控制流怎麼實現的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除