九、求值循环

CPython 如何解析并执行 Code Object。

到本章为止,你已经了解了如何将 Python 代码解析为抽象语法树并将其编译成 code object,这些 code object 包含了以字节码形式表示且相互独立的一系列操作。但要执行 code object 还缺少一项关键的内容,它们需要输入。在 Python 中,输入可能以局部变量或全局变量的形式出现。在本章中,你将接触到一个名为值栈(value stack) 的概念。在你编译的 code object 中,字节码操作会在值栈创建、修改并使用变量。

CPython 中执行代码的动作发生在一个核心循环中,这个循环又被称为求值循环 (evaluation loop)。CPython 解释器将在该循环中解析并执行由序列化的 .pyc 文件或由编译器得到的 code object:

图字翻译 Parser:解析器 AST:抽象语法树 Compiler:编译器 CFG:控制流图 Assembler:汇编器 Bytecode:字节码 Execution:执行

在求值循环中,每一个字节码指令都是使用基于系统的 “栈帧” 获取和执行的。

不只 Python 中,许多运行时都使用了**栈帧(stack frame)**这种数据结构。栈帧保证了可以调用函数并获取返回值,它包含了参数、局部变量和其他一些状态信息。

每次调用函数时都会创建一个栈帧,这些栈帧按调用顺序堆叠在一起。如果抛出了未处理的异常,你就可以看到 CPython 的帧栈信息:

Traceback (most recent call last):
    File "example_stack.py", line 8, in <module> <--- Frame
        function1()
    File "example_stack.py", line 5, in function1 <--- Frame
        function2()
    File "example_stack.py", line 2, in function2 <--- Frame
        raise RuntimeError
    RuntimeError

相关的源文件

以下是与求值循环相关的源文件:

重要术语

以下是你将在本章中使用的几个重要术语:

  • 求值循环将会获取一个 code object 并将其转换为一系列的 frame object

  • 解释器至少需要一个线程

  • 每个线程都有自己的线程状态(thread state)

  • frame object 在被称为**帧栈(frame stack)**的栈中执行;

  • 变量在值栈中被引用。

Last updated