Python代码执行分三步:先编译为跨平台字节码(存于__pycache__),再由C实现的Python虚拟机逐条解释执行(受GIL限制),最后运行时按LEGB规则动态查名字并自动处理异常清理。

Python代码不是直接运行的,而是经过解释器层层处理后才真正执行。理解这个过程,能帮你写出更高效、更易调试的程序。
源代码 → 字节码:编译阶段
当你运行 python script.py,Python解释器(CPython)第一步不是执行,而是把.py文件编译成字节码(bytecode),保存在 __pycache__ 目录下的 .pyc 文件中。字节码是一种中间表示,类似汇编语言,但面向的是Python虚拟机(PVM),不是CPU。
- 同一份源码在不同平台生成的字节码基本一致(跨平台基础)
- 如果.py文件没变,且.pyc存在、时间戳更新,解释器会跳过编译,直接加载字节码
- 可用 compile() 函数手动触发编译,用 dis.dis() 查看字节码指令
字节码 → 实际执行:解释阶段
编译完成后,Python虚拟机(PVM)逐条读取字节码指令,查表匹配对应C函数,调用底层C实现来完成操作。比如 LOAD_NAME 指令会去当前作用域查找变量名,BINARY_ADD 会调用整数或字符串的加法逻辑。
- PVM本身是用C写的(CPython),所以执行效率依赖C层优化
- 没有JIT编译(如PyPy有),纯解释执行——这也是CPython启动快但长期计算慢的原因之一
- 全局解释器锁(GIL)在此阶段起作用,确保同一时刻只有一个线程执行字节码
名字查找与作用域:动态解析的关键
Python不靠编译时绑定变量,而是在运行时按 LEGB规则(Local → Enclosing → Global → Built-in)实时查找名字。这意味着:
立即学习“Python免费学习笔记(深入)”;
- eval() 和 exec() 的作用域行为容易出错,因为它们默认使用调用者的局部命名空间
- 函数内赋值即声明局部变量,哪怕写在if块里也会让同名外部变量不可见(UnboundLocalError)
- import语句也是运行时执行的,模块对象被缓存到 sys.modules 中
异常与清理:执行末尾的隐式动作
代码执行结束前,解释器会自动处理几类清理工作:
- 局部变量引用计数归零 → 触发 __del__(若定义且无循环引用)
- with语句块退出 → 自动调用 __exit__
- try/except/finally中,finally总会在离开该块前执行(包括遇到return、break、异常未被捕获时)
- 程序退出时,所有模块级对象被销毁,但顺序不确定,不建议依赖模块级 __del__
整个过程看似抽象,但每一步都影响着代码的行为、性能和可维护性。看清字节码、理解作用域、留意清理时机,比死记语法更能帮你避开坑。










