Python 底層運作 01 – 虛擬機器與 Byte Code

你可曾想過這段 Python 程式碼是如何運作的?

Python 作為 interpreted language,其運作可以分為兩個大項,Compiler 以及 Virtual Machine。Compiler 負責將輸入的語法做分析,轉換成 AST (Abstract Syntax Tree),再轉換成 CFG,最後依照 CFG 輸出 bytecode,Code Object 等必要的物件。Virtual Machine 則根據 bytecode 來運行,最後輸出程式運行的結果。

我們可以透過 Python 的 dis 模組,來得知程式碼的 Byte Code 是什麼:

詳細的 Byte Code 資訊可以到 32.12 dis – Disassembler for Python bytecode

第一行 a = 5 對應的是 LOAD_CONST 以及 STORE_NAME 這兩個 bytecode,透過 LOAD_CONST 將 const 放置到 stack top,接著 STORE_NAME 把 stack top 的 value 存到 a 這個變數名稱。第二行也是相同,第三行比較長,兩個 LOAD_NAME 之後使用 BINARY_ADD 將 stack top 以及 second 的數值相加後放回 stack top,使用 STORE_NAME 存到 c 變數中。最後的 LOAD_CONST (None) 以及 RETURN_VALUE 是附加上去的,跟三行程式碼沒有關係。

從這邊可以看出為什麼 Python 被稱為 dynamic type 的語言,在 VM 運行 bytecode 之前,Compiler 對型態是不會做檢查的。LOAD_CONST 並不只能用於 integer,string 也通用,BINARY_ADD 也是,不論前面 LOAD_NAME 的變數型態為何,BINARY_ADD 都可以執行。型態檢查只會在 bytecode 的實作中執行:

前面提到 STORE_NAME 的時候用了「存」這個字,我覺得並沒有很精確,應該用 「bind」或是「set」來指涉。簡單來說,你可以想成 locals_variables[name] = stack_top() ,因為牽扯到 frame,這邊不細談。

理論上,你可以用 Python 簡單的寫一個 VM 出來執行上面的 bytecode,也確實有人寫出來,可以參考 nedbat/byterun 以及 Allison Kaptur – Bytes in the Machine

總結而言,CPython 實作了一個 Python Virtual Machine,透過這個 VM 解讀bytecode,變能夠運行程式。至於 CPython 如何實作,可以參考 Python/ceval.c,簡單來說,就是一個 for(;;) 加上超級大的 switch。




如果你覺得這篇文章不錯,歡迎打賞 IOTA:RFHEIVXVIZWJFXTZORZZRCMHZF9PSGFUFWAAKXTFNZE9JQUY9HFQREJYYSPSXDRLECKXCAQQDOMSMYJYDKPCKWXBKD

或是點選下方圖片贊助我一杯咖啡:

Leave a reply:

Your email address will not be published.

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料