Python是先编译为字节码再由虚拟机解释执行的混合型语言,CPython将.py源码编译成.pyc字节码并缓存,由PVM执行;字节码版本特定、不可跨实现通用,需PyInstaller等工具生成真正可执行文件。

Python 并不是纯粹的“解释执行”,也不是传统意义上的“编译执行”,而是先编译成字节码,再由虚拟机解释执行。这个过程常被简化为“解释型语言”,但背后有明确的编译环节,只是不生成本地机器码,也不暴露给用户。
Python 会编译,只是不生成 .exe 或二进制文件
当你运行 python script.py 时,CPython(最常用的 Python 解释器)会:
- 先将源代码(.py 文件)解析成抽象语法树(AST)
- 再把 AST 编译成平台无关的字节码(bytecode),保存在
__pycache__/script.cpython-312.pyc中(版本号随 Python 版本变化) - 最后由 Python 虚拟机(PVM)逐条读取并执行这些字节码指令
这个编译步骤是自动、隐式且快速的。如果 .py 文件没变,下次运行会直接加载已缓存的 .pyc 文件,跳过编译阶段。
字节码不是机器码,也不能跨 Python 版本运行
Python 字节码是为 CPython 虚拟机设计的中间表示,不是 CPU 能直接执行的指令:
立即学习“Python免费学习笔记(深入)”;
Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。它虽然不是Linux系统核心的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。因此,对于用户来说,shell是最重要的实用程序,深入了解和熟练掌握shell的特性极其使用方法,是用好Linux系统
- 不同 Python 版本(如 3.11 和 3.12)的字节码格式可能不同,所以 .pyc 文件不能通用
- PyPy、Jython、MicroPython 等其他实现有各自的字节码或执行机制,互不兼容
- 你可以用
dis模块查看字节码:import dis; dis.dis(lambda x: x + 1)
真正的“编译执行”需要额外工具
若想得到真正可脱离 Python 环境运行的二进制程序,得借助第三方工具,它们做了更深层的编译或打包:
- PyInstaller / cx_Freeze:把 Python 解释器、字节码、依赖库一起打包成可执行文件,运行时仍需解压并启动内置的 PVM
- Cython:将 .py 或 .pyx 文件翻译成 C 代码,再调用 C 编译器生成扩展模块(.so 或 .dll),这部分是原生机器码,可被 Python 导入调用
- Nuitka:真正将 Python 代码整体编译为 C++ 代码,再编译成二进制,能生成独立可执行文件,也支持进一步优化
为什么说“解释执行”仍是主流理解?
因为对开发者而言,没有显式的编译命令(如 gcc main.c -o main),也没有手动管理字节码的必要:
- 源码修改后立即生效,无需重新编译整个项目
- 交互式环境(如 IPython、REPL)中,输入即编译即执行,延迟极低
- 错误提示指向原始 .py 行号,调试体验贴近“纯解释”
这种“隐藏编译 + 显式解释”的混合模型,兼顾了开发效率与一定运行效率,也是 Python 设计哲学的体现。









