Python虛擬機(jī)字節(jié)碼教程之控制流實(shí)現(xiàn)詳解
控制流實(shí)現(xiàn)
控制流這部分代碼主要涉及下面幾條字節(jié)碼指令,下面的所有字節(jié)碼指令都會(huì)有一個(gè)參數(shù):
- JUMP_FORWARD,指令完整條指令會(huì)將當(dāng)前執(zhí)行字節(jié)碼指令的位置加上這個(gè)參數(shù),然后跳到對(duì)應(yīng)的結(jié)果繼續(xù)執(zhí)行。
- POP_JUMP_IF_TRUE,如果棧頂元素等于 true,將字節(jié)碼的執(zhí)行位置改成參數(shù)的值。將棧頂元素彈出。
- POP_JUMP_IF_FALSE,這條指令和 POP_JUMP_IF_TRUE 一樣,唯一差別就是判斷棧頂元素是否等于 true。
- JUMP_IF_TRUE_OR_POP,如果棧頂元素等于等于 true 則將字節(jié)碼執(zhí)行位置設(shè)置成參數(shù)對(duì)應(yīng)的值,并且不需要將棧頂元素彈出。但是如果棧頂元素是 false 的話那么就需要將棧頂元素彈出。
- JUMP_IF_FALSE_OR_POP,和JUMP_IF_TRUE_OR_POP一樣只不過需要棧頂元素等于 false 。
- JUMP_ABSOLUTE,直接將字節(jié)碼的執(zhí)行位置設(shè)置成參數(shù)的值。
總的來說,這些跳轉(zhuǎn)指令可以讓 Python 的解釋器在執(zhí)行字節(jié)碼時(shí)根據(jù)特定條件來改變執(zhí)行流程,實(shí)現(xiàn)循環(huán)、條件語句等基本語言結(jié)構(gòu)。
現(xiàn)在我們使用一個(gè)例子來深入理解上面的各種指令的執(zhí)行過程。
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__ == '__main__':
dis.dis(test_control01)
上面的程序輸出結(jié)果如下所示:
6 0 LOAD_CONST 1 (1)
2 STORE_FAST 0 (a)
8 4 LOAD_FAST 0 (a)
6 LOAD_CONST 1 (1)
8 COMPARE_OP 4 (>)
10 POP_JUMP_IF_FALSE 22
9 12 LOAD_GLOBAL 0 (print)
14 LOAD_CONST 2 ('a > 1')
16 CALL_FUNCTION 1
18 POP_TOP
20 JUMP_FORWARD 26 (to 48)
10 >> 22 LOAD_FAST 0 (a)
24 LOAD_CONST 1 (1)
26 COMPARE_OP 0 (<)
28 POP_JUMP_IF_FALSE 40
11 30 LOAD_GLOBAL 0 (print)
32 LOAD_CONST 3 ('a < 1')
34 CALL_FUNCTION 1
36 POP_TOP
38 JUMP_FORWARD 8 (to 48)
13 >> 40 LOAD_GLOBAL 0 (print)
42 LOAD_CONST 4 ('a == 1')
44 CALL_FUNCTION 1
46 POP_TOP
>> 48 LOAD_CONST 0 (None)
50 RETURN_VALUE
我們現(xiàn)在來模擬一下上面的字節(jié)碼執(zhí)行過程,我們使用 counter 表示當(dāng)前字節(jié)碼的執(zhí)行位置:
在字節(jié)碼還沒開始執(zhí)行之前,??臻g和 counter 的狀態(tài)如下:

現(xiàn)在執(zhí)行第一條字節(jié)碼 LOAD_CONST,執(zhí)行完之后 counter = 2,因?yàn)檫@條字節(jié)碼占一個(gè)字節(jié),參數(shù)棧一個(gè)字節(jié),因此下次執(zhí)行的字節(jié)碼的位置在 bytecode 的低三個(gè)位置,對(duì)應(yīng)的下標(biāo)為 2,因此 counter = 2 。

現(xiàn)在執(zhí)行第二條字節(jié)碼 STORE_FAST,讓 a 指向 1 ,同樣的 STORE_FAST 操作碼和操作數(shù)各占一個(gè)字節(jié),因此執(zhí)行完這條字節(jié)碼之后??臻g沒有數(shù)據(jù),counter = 4 。

接下來 LOAD_FAST 將 a 指向的對(duì)象也就是 1 加載進(jìn)入棧中,此時(shí)的 counter = 6,LOAD_CONST 將常量 1 加載進(jìn)行入??臻g當(dāng)中,此時(shí) counter = 8,在執(zhí)行完這兩條指令之后,??臻g的變化如下圖所示:

接下來的一條指令是 COMPARE_OP ,這個(gè)指令有一個(gè)參數(shù)表示比較的符號(hào),這里是比較 a > 1,并且會(huì)將比較的結(jié)果壓入棧中,比較的結(jié)果是 false ,因?yàn)?COMPARE_OP 首先會(huì)將??臻g的兩個(gè)輸入彈出,因此在執(zhí)行完這條指令之后??臻g和 counter 的值如下:

下面一條指令為 POP_JUMP_IF_FALSE,根據(jù)前面的字節(jié)碼含義,這個(gè)字節(jié)碼會(huì)將棧頂?shù)?false 彈出,并且會(huì)進(jìn)行跳轉(zhuǎn),并且將 counter 的值直接編程參數(shù)的值,這里他的參數(shù)是 22 ,因此 counter = 22,在執(zhí)行完這條指令之后,結(jié)果如下:

因?yàn)楝F(xiàn)在已經(jīng)跳轉(zhuǎn)到了 22 ,因此接下來執(zhí)行的指令為 LOAD_FAST,將變量 a 加載進(jìn)入??臻g,LOAD_CONST 將常量 1 加載進(jìn)入??臻g,在執(zhí)行完這兩條執(zhí)行之后,變化情況如下:

在次執(zhí)行 POP_JUMP_IF_FALSE,這回的結(jié)果也是 false ,因此繼續(xù)執(zhí)行 POP_JUMP_IF_FALSE,這次的參數(shù)是 40,直接將 counter 的值設(shè)置成 40 。

接下來 LOAD_GLOBAL 加載一個(gè)全局變量 print 函數(shù) counter 變成 42 ,LOAD_CONST 加載字符串 "a == 1" 進(jìn)入棧空間,counter = 44,此時(shí)狀態(tài)如下:

CALL_FUNCTION 這個(gè)字節(jié)碼有一個(gè)參數(shù),表示調(diào)用函數(shù)的參數(shù)的個(gè)數(shù),這里是 1,因?yàn)?print 函數(shù)只有一個(gè)參數(shù),然后輸出字符串 "a== 1",但是這里需要注意的是 print 函數(shù)會(huì)返回一個(gè) None,因此執(zhí)行完 CALL_FUNCTION 之后狀態(tài)如下:

至此差不多上面的函數(shù)差不多執(zhí)行完了,后面幾條字節(jié)碼很簡(jiǎn)單,就不再進(jìn)行敘述了。
總結(jié)
在 Python 中,控制流指令可以讓解釋器根據(jù)特定條件改變執(zhí)行流程,實(shí)現(xiàn)循環(huán)、條件語句等基本語言結(jié)構(gòu)。Python 中與控制流有關(guān)的字節(jié)碼指令包括 JUMP_FORWARD、POP_JUMP_IF_TRUE、POP_JUMP_IF_FALSE、JUMP_IF_TRUE_OR_POP、JUMP_IF_FALSE_OR_POP 和 JUMP_ABSOLUTE 等。這些指令都有一個(gè)參數(shù),主要是用來計(jì)算跳轉(zhuǎn)的目標(biāo)位置等。通過對(duì)這些指令的了解,我們可以更深入地理解 Python 字節(jié)碼的執(zhí)行過程和控制流實(shí)現(xiàn)原理。
到此這篇關(guān)于Python虛擬機(jī)字節(jié)碼教程之控制流實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)Python字節(jié)碼控制流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python使用opencv實(shí)現(xiàn)馬賽克效果示例
這篇文章主要介紹了python使用opencv實(shí)現(xiàn)馬賽克效果,結(jié)合實(shí)例形式分析了Python使用cv2模塊操作圖片實(shí)現(xiàn)馬賽克效果的相關(guān)技巧,需要的朋友可以參考下2019-09-09
Python3 實(shí)現(xiàn)減少可調(diào)用對(duì)象的參數(shù)個(gè)數(shù)
今天小編就為大家分享一篇Python3 實(shí)現(xiàn)減少可調(diào)用對(duì)象的參數(shù)個(gè)數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-12-12
利用Python實(shí)現(xiàn)Windows下的鼠標(biāo)鍵盤模擬的實(shí)例代碼
本篇文章主要介紹了利用Python實(shí)現(xiàn)Windows下的鼠標(biāo)鍵盤模擬的實(shí)例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-07-07
Python實(shí)現(xiàn)內(nèi)網(wǎng)穿透和端口轉(zhuǎn)發(fā)代理詳解
這篇文章主要為大家介紹了Python實(shí)現(xiàn)內(nèi)網(wǎng)穿透和端口轉(zhuǎn)發(fā)代理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12

