python实现解释器_Python 解释器初探
A Python Interpreter Written in Python 是一篇很棒的文章,作者用 Python 實現了一個 Python 解釋器(Byterun),文章的前半部分講解 Python 解釋器的基本結構,實現一個玩具(簡易指令集)解釋器。
有時候我們把 Python 解釋執行的整個流程都叫做 Python 解釋器,它包含以下幾步:
lexer
parser
compiler
interpreter
以源碼文本作為輸入,1, 2, 3 步后得到 code object,并作為第 4 步的輸入,我們這里討論的解釋器只針對第 4 步。
可能需要說明的是,為什么 Python 作為解釋語言還有 compiler 呢,其實所謂解釋語言,只是在編譯步做相對(編譯語言,如 C,Java)少的工作。
從性質上說,Python 解釋器是一個 virtual machine,也是一個 bytecode interpreter。而 virtual machine 又可以分為基于棧(stack)的和基于寄存器(register)的,Python 解釋器屬于前者。
對于 Python 解釋器的輸入 code object,它是一個包含 bytecode 的對象,而 bytecode 是一組指令,是 Python 代碼的 IR。
以 7+5 為例,用一組玩具指令表示如下,其中 what_to_execute 就是 code object,instructions 就是 bytecode。
what_to_execute = {
"instructions": [
("LOAD_VALUE", 0), # the first number
("LOAD_VALUE", 1), # the second number
("ADD_TWO_VALUES", None),
("PRINT_ANSWER", None)
],
"numbers": [7, 5]
}
再加上變量的處理,就可以得到這個玩具 Python 解釋器了。
class Interpreter:
def __init__(self):
self.stack = []
self.environment = {}
def LOAD_VALUE(self, number):
self.stack.append(number)
def PRINT_ANSWER(self):
answer = self.stack.pop()
print(answer)
def ADD_TWO_VALUES(self):
first_num = self.stack.pop()
second_num = self.stack.pop()
total = first_num + second_num
self.stack.append(total)
def STORE_NAME(self, name):
val = self.stack.pop()
self.environment[name] = val
def LOAD_NAME(self, name):
val = self.environment[name]
self.stack.append(val)
def parse_argument(self, instruction, argument, what_to_execute):
""" Understand what the argument to each instruction means. """
numbers = ["LOAD_VALUE"]
names = ["LOAD_NAME", "STORE_NAME"]
if instruction in numbers:
argument = what_to_execute["numbers"][argument]
elif instruction in names:
argument = what_to_execute["names"][argument]
return argument
def run_code(self, what_to_execute):
instructions = what_to_execute["instructions"]
for each_step in instructions:
instruction, argument = each_step
argument = self.parse_argument(instruction, argument, what_to_execute)
if instruction == "LOAD_VALUE":
self.LOAD_VALUE(argument)
elif instruction == "ADD_TWO_VALUES":
self.ADD_TWO_VALUES()
elif instruction == "PRINT_ANSWER":
self.PRINT_ANSWER()
elif instruction == "STORE_NAME":
self.STORE_NAME(argument)
elif instruction == "LOAD_NAME":
self.LOAD_NAME(argument)
# better run_code making use of Python's dynamic method lookup
def execute(self, what_to_execute):
instructions = what_to_execute["instructions"]
for each_step in instructions:
instruction, argument = each_step
argument = self.parse_argument(instruction, argument, what_to_execute)
bytecode_method = getattr(self, instruction)
if argument is None:
bytecode_method()
else:
bytecode_method(argument)
what_to_execute = {
"instructions": [("LOAD_VALUE", 0),
("STORE_NAME", 0),
("LOAD_VALUE", 1),
("STORE_NAME", 1),
("LOAD_NAME", 0),
("LOAD_NAME", 1),
("ADD_TWO_VALUES", None),
("PRINT_ANSWER", None)],
"numbers": [1, 2],
"names": ["a", "b"]}
interpreter = Interpreter()
interpreter.run_code(what_to_execute)
在 Python 中對于一個函數對象 obj 我們可以使用 obj.__code__ 得到 code object,obj.__code__.co_code 得到 bytecode。但實際的輸出可能是不可讀的(字節),可以利用 Python dis 模塊(bytecode disassembler)中的 dis.opname(n) 得到字節對應的字符串,也可以直接用 dis.dis(obj) 輸出函數對象字節碼的解釋。
后半部分過度到真實的 Python bytecode,其中關于 frames 的部分非常值得一讀。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的python实现解释器_Python 解释器初探的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python建模分析实操_R和Pytho
- 下一篇: modbus 0x06 连续写_这篇很实