跳到主要内容

请解释 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)

执行步骤:

  1. 词法分析 → 识别 def、square、(、n、)、: 等 Token
  2. 语法分析 → 构建函数定义节点、调用节点、赋值节点的 AST
  3. 编译 → 生成 MAKE_FUNCTION、CALL_FUNCTION、BINARY_MULTIPLY 等字节码
  4. PVM 执行 → 创建函数对象、压栈参数 4、执行乘法、打印结果 16

总结​

阶段输入输出工具
词法分析源代码字符串Token 流tokenize 模块
语法分析Token 流ASTast 模块
编译AST字节码compile()、dis 模块
执行字节码运行结果CPython PVM

Python 是解释型语言,但并非直接解释源码——它先编译为字节码,再由虚拟机解释执行,兼顾了开发效率和一定的运行性能。