python执行代码分两阶段:先编译源码为字节码,再由pvm解释执行;过程包括源码解析成ast、ast编译为.pyc字节码、pvm驱动栈帧运行指令,并通过.pyc缓存优化重复导入。

Python解释器执行代码时,并不是直接运行源码,而是先将源码编译成字节码(bytecode),再由Python虚拟机(PVM)逐条解释执行字节码。这个“编译→解释”两阶段流程是CPython的核心机制。
源码解析:从 .py 文件到抽象语法树(AST)
当你运行 python script.py,解释器首先读取源文件,进行词法分析(tokenization)和语法分析(parsing),生成一棵抽象语法树(AST)。这一步检查语法是否合法,比如括号是否匹配、冒号是否缺失、缩进是否一致等。如果语法错误,就在此阶段报错(如 SyntaxError),不会继续后续步骤。
字节码生成:AST 编译为 .pyc 中的指令序列
AST 被送入编译器模块,转换为平台无关的字节码——一种精简的指令集(如 LOAD_NAME、BINARY_ADD、RETURN_VALUE)。这些指令被序列化后保存在 __pycache__/script.cpython-312.pyc 文件中(版本号随 Python 版本变化)。你可用内置函数 compile() 手动触发该过程:
>>> code = compile('a = 1 + 2', '<string>', 'exec')
>>> code.co_code # 字节码原始字节
b'd\x01\x00d\x02\x00\x17\x00Z\x00\x00'
>>> import dis
>>> dis.dis(code) # 反汇编查看可读指令
1 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (2)
4 BINARY_ADD
6 STORE_NAME 0 (a)
8 LOAD_CONST 0 (None)
10 RETURN_VALUE字节码执行:PVM 驱动栈帧运行
字节码不直接映射到机器码,而是由 Python 虚拟机(纯 C 实现的循环解释器)读取并执行。PVM 维护运行时栈、局部变量表、块栈等结构。每条字节码指令操作这些数据结构——例如 LOAD_CONST 将常量压入栈顶,BINARY_ADD 弹出两个操作数相加后再压入。函数调用会创建新栈帧(frame),实现作用域隔离与递归支持。
立即学习“Python免费学习笔记(深入)”;
优化与缓存:.pyc 文件如何被复用
首次导入模块时,CPython 自动生成 .pyc 并缓存。下次导入时,若源文件时间戳未变且 Python 版本兼容,就跳过编译,直接加载字节码。可通过 -B 参数禁止写 .pyc,或用 py_compile 模块预编译:
-
python -m py_compile script.py→ 生成__pycache__/script.cpython-312.pyc -
python -B -m compileall .→ 递归编译整个目录,不生成 .pyc - 修改源码或切换 Python 版本后,.pyc 自动失效并重建










