请解释 Python 代码的执行过程?
总体流程
源代码 (.py)
│
▼
① 词法分析(Lexer)→ Token 流
│
▼
② 语法分析(Parser)→ AST(抽象语法树)
│
▼
③ 编译(Compiler)→ 字节码(Bytecode)+ .pyc 文件
│
▼
④ 解释执行(PVM)→ 运行结果
各阶段详解
① 词法分析(Tokenize)
将源代码文本拆分为一个个 Token(词法单元):
# 源代码
x = 1 + 2
NAME 'x'
OP '='
NUMBER '1'
OP '+'
NUMBER '2'
NEWLINE
import tokenize, io
code = "x = 1 + 2"
tokens = tokenize.generate_tokens(io.StringIO(code).readline)
for tok in tokens:
print(tok)
② 语法分析(Parse)→ AST
将 Token 流解析为抽象语法树(Abstract Syntax Tree):
import ast
code = "x = 1 + 2"
tree = ast.parse(code)
print(ast.dump(tree, indent=2))
输出结构大致为:
Module
└── Assign
├── targets: [Name('x')]
└── value: BinOp
├── left: Constant(1)
├── op: Add
└── right: Constant(2)
③ 编译 → 字节码
AST 被编译为 字节码(Bytecode),并缓存为 .pyc 文件(位于 __pycache__/):
import dis
def add(a, b):
return a + b
dis.dis(add)
2 0 LOAD_FAST 0 (a)
2 LOAD_FAST 1 (b)
4 BINARY_ADD
6 RETURN_VALUE
字节码是平台无关的中间表示,由 Python 虚拟机(PVM)执行。
④ Python 虚拟机(PVM)执行
PVM(Python Virtual Machine)是一个基于栈的解释器,逐条执行字节码指令:
LOAD_FAST a → 将 a 压栈
LOAD_FAST b → 将 b 压栈
BINARY_ADD → 弹出两个值相加,结果压栈
RETURN_VALUE → 弹出栈顶作为返回值
.pyc 缓存文件
project/
├── main.py
└── __pycache__/
└── main.cpython-311.pyc ← 字节码缓存
- 首次运行时生成,后续如果
.py未修改则直接加载.pyc,跳过编译阶段 - 文件名包含 Python 版本信息,不同版本互不兼容
- 可用
python -B禁止生成.pyc
CPython vs 其他实现
| 实现 | 说明 |
|---|---|
| CPython(默认) | C 实现,编译为字节码后由 PVM 解释执行 |
| PyPy | 含 JIT 编译器,热点代码编译为机器码,速度更快 |
| Jython | 编译为 JVM 字节码,运行在 Java 虚拟机上 |
| MicroPython | 面向嵌入式设备的轻量实现 |
GIL(全局解释器锁)
CPython 的 PVM 在执行字节码时受 GIL(Global Interpreter Lock) 保护:
- 同一时刻只有一个线程执行 Python 字节码
- CPU 密集型任务用多线程无法真正并行,需用多进程(
multiprocessing) - I/O 密集型任务线程会主动释放 GIL,多线程有效
Python 3.13+ 开始支持「无 GIL 模式」(实验性)
完整示例追踪
# example.py
def square(n):
return n * n
result = square(4)
print(result)
执行步骤:
- 词法分析 → 识别
def、square、(、n、)、:等 Token - 语法分析 → 构建函数定义节点、调用节点、赋值节点的 AST
- 编译 → 生成
MAKE_FUNCTION、CALL_FUNCTION、BINARY_MULTIPLY等字节码 - PVM 执行 → 创建函数对象、压栈参数 4、执行乘法、打印结果 16
总结
| 阶段 | 输入 | 输出 | 工具 |
|---|---|---|---|
| 词法分析 | 源代码字符串 | Token 流 | tokenize 模块 |
| 语法分析 | Token 流 | AST | ast 模块 |
| 编译 | AST | 字节码 | compile()、dis 模块 |
| 执行 | 字节码 | 运行结果 | CPython PVM |
Python 是解释型语言,但并非直接解释源码——它先编译为字节码,再由虚拟机解释执行,兼顾了开发效率和一定的运行性能。