解释器是什么?
解释器是一种直接执行源代码的程序,它边读边执行其中的指令,而不是先把整个程序翻译成一个单独的机器码文件。Python 和 Ruby 的标准实现都是解释器。
更新于 2026年9月24日
- 1print("Hello")
- 2total = 2 + 3
- 3print(total)
- 4print("Done")
每次运行都要重新翻译所有代码行。打开拼写错误后,解释器仍然会先输出“Hello”,到第 3 行才停下来。
输入 python3 hello.py,输出就出现了,但之后看看文件夹:并没有生成新的程序文件。真正运行的程序是 python3 本身,也就是 Python 解释器。它读取 hello.py,弄清每条语句的含义,然后执行它。明天再运行这个脚本,解释器又会从头读取一遍源代码。
解释器是如何工作的
解释器不断重复一个循环,直到程序结束:取出下一条指令,弄清它的含义,执行它,然后继续。工作过程中,它把程序的变量保存在自己的内存里,所以 total = price * 3 才能用上几行之前设置的 price。
最直观的观察方式是交互模式,也叫 REPL(读取、求值、打印、循环)。不带文件名输入 python3,每按一次回车,那一行就会立即运行:
>>> price = 4
>>> price * 3
12
真正的解释器还多了一个准备步骤。标准的 Python 解释器 CPython 会先把整个文件编译成字节码,也就是一串紧凑的简单指令,然后运行一个循环,每次执行一条字节码指令。你可以打印出一行代码对应的字节码:
Python 3.12 会打印出下面的内容(其他版本在细节上有所不同):
0 0 RESUME 0
1 2 LOAD_NAME 0 (price)
4 LOAD_CONST 0 (3)
6 BINARY_OP 5 (*)
10 STORE_NAME 1 (total)
12 RETURN_CONST 1 (None)
其中每一行都是解释器循环中的一步:取出 price 的值,取出常量 3,把它们相乘,把结果存入 total。这些都不是机器码;执行每一步的是解释器,而解释器本身是一个编译好的 C 程序。
错误在那一行运行时才出现
由于解释器是边读边执行的,程序在遇到错误之前已经可以做一些实际的工作了。运行下面的代码,崩溃前会先打印出前两行:
Step 1: starting
Step 2: still fine
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
语法错误的表现则不同,因为 CPython 在运行任何代码之前,会先把整个文件编译成字节码。把第 3 行改成 print("Step 3:" 10)(漏了逗号),就什么都不会打印,连 Step 1 也不会:
SyntaxError: invalid syntax. Perhaps you forgot a comma?
所以“解释器逐行运行代码”这种说法只对了一半。语法会先针对整个文件进行检查;其他错误,比如除以零或使用不存在的名字,只有在那一行执行时才会被发现。第一类错误请参阅语法错误。
编译器和解释器的区别
编译器在程序运行之前,把整个程序翻译成一个单独的文件。解释器则每次都亲自运行程序。两者在实际使用中的差异都由此而来:
| 编译器 | 解释器 | |
|---|---|---|
| 工作发生在何时 | 程序运行前一次完成 | 程序每次运行时都要做 |
| 输出 | 一个单独的文件(可执行文件或字节码) | 没有单独的程序文件 |
| 交给用户的是什么 | 编译好的程序 | 源代码,外加用户电脑上安装的解释器 |
| 错误检查 | 运行前检查整个程序的语法,在类型化语言中还检查类型错误 | 通常先检查语法;其他错误在出错的那一行运行时才出现 |
| 修改后运行 | 每次修改后都要重新编译 | 保存后直接再次运行 |
| 速度 | 更快,CPU 直接运行机器码 | 更慢,每条指令都要在程序运行时解码 |
| 可移植性 | 需要为每种 CPU 和操作系统重新编译 | 同一份源代码在任何装有解释器的地方都能运行 |
| 典型语言 | C、C++、Rust、Go | Python、Ruby、PHP、Bash |
对于密集的算术循环,速度差距确实存在:同一个循环用编译后的 C 运行,可能比在 CPython 中快很多倍。但对于大部分时间都在等待网络、磁盘或用户的程序,这种差异往往小到察觉不出来。
编译型还是解释型,并不是语言本身的属性
语言是一套规则;编译器或解释器则是实现这些规则的程序。同一门语言可以用两种方式运行,而大多数流行语言都把两者结合了起来:
- Python。 CPython 先编译成字节码,再解释执行。另一种实现 PyPy 加入了即时(JIT)编译器,在程序运行时把频繁执行的代码转换成机器码。
- Java。
javac提前把源代码编译成字节码。然后由 Java 虚拟机解释执行这些字节码,并把最繁忙的方法 JIT 编译成机器码。从 Java 11 开始,java Main.java可以先在内存中编译单个源文件,然后直接运行它。 - JavaScript。 浏览器和 Node.js 使用 V8 等引擎,它们一开始解释执行代码,并在程序运行过程中把热点部分编译成机器码。
- C 和 C++。 几乎总是用 GCC、Clang 或 MSVC 提前编译。
python3 app.py # Python: interpreter, bytecode behind the scenes
node app.js # JavaScript: V8 interprets, then JIT-compiles
javac Main.java # Java step 1: compile to Main.class
java Main # Java step 2: the JVM runs the bytecode
无论哪种情况,解释器或虚拟机都是程序运行时环境的一部分:程序在哪里运行,就必须在哪里安装它。
常见误解
- “解释器把每一行都翻译成机器码。” 经典的解释器从来不会为你的程序生成机器码。它读取一条指令,然后用解释器中早已编译好的代码去执行它。在运行时生成机器码,是 JIT 编译器做的事。
- “解释型语言没有编译步骤。” CPython、Ruby 的 YARV 和 PHP 都会先编译成字节码。这个步骤是自动且不可见的,所以很容易被忽略。
- “解释型就意味着慢。” JIT 编译大大缩小了差距。V8 运行 JavaScript 的速度足以支撑大型应用,比如基于 Electron 构建的 VS Code。
- “Python 就是解释器。” Python 是语言。CPython、PyPy 和 MicroPython 是它的不同解释器,它们在速度和支持的库上都可能不同。
下一步学什么
想了解对比的另一半,可以阅读编译器是什么,看看它如何把源代码变成机器码。运行时环境页面解释了解释器还会带来哪些东西。想亲自试试解释器,可以运行一个 Python 脚本,或者打开 Python 在线编辑器。
常见问题
Python 是编译器还是解释器?
Python 是一门语言;运行它的程序通常是 CPython,而 CPython 是一个解释器。CPython 会先自动把你的代码编译成字节码,再解释执行这些字节码。Python 还有其他实现,比如加入了 JIT 编译器的 PyPy。
C++ 是解释器还是编译器?
C++ 是一门语言,它几乎总是用 GCC、Clang 或 MSVC 这样的编译器提前编译。编译结果是针对某一种 CPU 和操作系统的原生可执行文件。C++ 也有交互式工具,但它们其实是在后台编译每一段代码。
解释器和编译器哪个更快?
编译后的程序通常运行得更快,因为 CPU 直接执行机器码,而不需要解释器逐步解码。解释器则启动更快,因为不需要单独的构建步骤。JVM 和 V8 使用的 JIT 编译器会在程序运行时编译最繁忙的代码,缩小了两者之间的差距。
REPL 是什么?
python3 或 node 就能打开一个 REPL。它很适合在不创建文件的情况下快速验证一个小想法。一门语言可以既是编译型又是解释型吗?
javac 编译成字节码,再由 JVM 解释执行并进行 JIT 编译;Python 和 JavaScript 等语言也同时有解释器和编译器。