运行时错误是什么?
运行时错误(runtime error)是程序运行过程中发生的错误:某个操作无法用当前的值完成,比如除以零,或者读取超出列表末尾的位置。除非错误被处理,否则程序会在这一行停下来。
更新于 2026年9月24日
运行时错误会一直等到程序已经运行起来才出现。代码在启动前通过了所有检查,正常运行了一段时间,然后遇到一个无法用当时的值完成的操作。下面这个函数对一个列表没问题,对另一个列表却会失败:
85.0
Traceback (most recent call last):
File "main.py", line 5, in <module>
print(average([]))
^^^^^^^^^^^
File "main.py", line 2, in average
return sum(scores) / len(scores)
~~~~~~~~~~~~^~~~~~~~~~~~~
ZeroDivisionError: division by zero
第一次调用打印 85.0。第二次调用传入了一个空列表,所以 len(scores) 是 0,除法无法进行。语法没有任何问题,所以这不是语法错误。问题只在某些数据下才存在,这就是为什么一个程序正常运行了一百次之后,仍然可能出现运行时错误。
运行时错误发生时会怎样
- 程序执行到一个操作,这里是
sum(scores) / len(scores)。 - 运行环境在执行之前先检查这个操作。CPython 在做除法前会检查除数,JVM 会检查每一个数组索引,Python 在返回字典的值之前会检查键是否存在。
- 检查没有通过,运行环境就创建一个错误对象。在 Python 和 Java 中,这个对象就是异常,它记录了错误类型、一条信息以及出错的位置。
- 运行环境寻找处理这类错误的代码,先在当前函数里找,再到调用它的函数里找,依次向外层查找。
- 如果没有任何代码处理它,程序就会停止。Python 打印一段 traceback,并以状态码 1 退出。Java 打印一段以
Exception in thread "main"开头的堆栈跟踪。
没有这些检查的语言表现就不一样了。C 语言不检查数组索引或指针,所以一次错误的内存访问要么悄悄地破坏数据,要么让操作系统以段错误终止程序。
程序在出错那一行之前做的所有事情都已经发生了。下面这个循环先打印了三种颜色,在第四次时才失败:
red
green
blue
Traceback (most recent call last):
File "main.py", line 4, in <module>
print(colors[i])
~~~~~~^^^
IndexError: list index out of range
如何阅读 traceback
Python 的 traceback 要从下往上读。最后一行写着错误类型和信息:ZeroDivisionError: division by zero。上面的几行列出了调用链,最早的在前,最近的在后。在第一个例子中,第 5 行调用了 average,而 average 内部的第 2 行就是除法失败的地方。
出错的那一行,并不总是需要修改的那一行。average 的第 2 行本身没有问题。真正的问题是空列表是怎么传到这里的,所以要顺着这个错误的值往回追,找到它的来源,在那里修复。如果 traceback 经过了不是你写的库文件,就找最后一行指向你自己文件的那一行。
常见的运行时错误
下面的每条信息都直接复制自 Python 3.12。
| 错误 | 示例 | 信息 |
|---|---|---|
ZeroDivisionError | 10 / 0 | division by zero |
IndexError | ["red", "green", "blue"][3] | list index out of range |
KeyError | {"theme": "dark"}["font"] | 'font' |
ValueError | int("twenty") | invalid literal for int() with base 10: 'twenty' |
TypeError | "Total: " + 5 | can only concatenate str (not "int") to str |
AttributeError | 对 None 调用 .upper() | 'NoneType' object has no attribute 'upper' |
FileNotFoundError | open("missing.txt") | [Errno 2] No such file or directory: 'missing.txt' |
RecursionError | 一个无限调用自身的函数 | maximum recursion depth exceeded |
Java 有直接对应的异常,比如 ArithmeticException、ArrayIndexOutOfBoundsException、NumberFormatException 和 NullPointerException。在 Java 中,一次没有被捕获的整数除以零会打印:
Exception in thread "main" java.lang.ArithmeticException: / by zero
JavaScript 对数字更宽容:10 / 0 的结果是 Infinity,而不是错误。它会在你使用一个不存在的值时出错。当 user 是 undefined 时,Node.js 对 user.name 打印:
TypeError: Cannot read properties of undefined (reading 'name')
如何修复运行时错误
- 复现它。用同样的输入再运行一次程序,确认出现的是同一个错误。
- 阅读 traceback 的最后一行,然后在你自己的代码里找到对应的行。
- 查看相关的值。在出错的那一行之前把它们打印出来,或者用调试器在那里设一个断点停下来。
- 修复根本原因。改正索引,为特殊情况加上保护,或者在使用输入之前先验证它。
对于 average 函数,修复办法是先决定没有任何成绩时平均分应该是多少,再把这个决定写进代码:
85.0
0
有些失败是你无法控制的:文件被删除了,网络超时了,用户在该填数字的地方输入了字母。这些情况没法靠修改代码来避免,所以要用异常处理捕获它们,再决定程序接下来怎么做。你不应该做的,是用 try 把一个 bug 包起来藏住。循环多数了一步导致的 IndexError 是需要修复的错误,而不是需要捕获的异常。
Windows 和 Excel 中的运行时错误信息
这个术语也会出现在你自己的代码之外。如果 Windows 弹出一个标题为 Microsoft Visual C++ Runtime Library、内容带有 Runtime Error! 字样的对话框,说明某个用 C++ 编写的程序遇到了致命错误,被 C++ 运行库终止了。作为用户,你无法修改那段代码,所以通常的解决办法是更新这个程序,修复或重新安装 Microsoft Visual C++ Redistributable 运行库,如果是游戏,还可以更新显卡驱动。
用 VBA 编写的 Excel 宏会报告带编号的运行时错误。Run-time error '9': Subscript out of range 表示宏请求了一个不存在的工作表或数组元素,Run-time error '1004' 则是对工作簿、工作表或区域的操作失败时抛出的通用错误。道理和 Python 中一样:合法的代码遇到了它无法处理的值。
下一步学什么
运行时错误有两个“兄弟”:在程序启动前就被发现的语法错误,以及从不产生任何信息的逻辑错误。想让程序从运行时错误中恢复而不是直接崩溃,可以阅读异常处理,再看 Python 指南中的异常和调试错误。Python 课程的每一课都会让你编写和修复这样的代码。
常见问题
运行时错误和语法错误有什么区别?
语法错误在程序启动前就会被发现,因为代码违反了语言的语法规则,所以一行都不会运行。运行时错误发生得更晚,是在程序运行过程中,某一行合法的代码遇到了它无法处理的值。在它之前的每一行都已经运行过,可能已经打印了输出。
为什么我总是遇到运行时错误?
通常是因为代码对数据做了并不总是成立的假设:列表永远不会是空的,文件一定存在,用户一定会输入数字。每个假设对你测试过的输入都成立,却会在某个你没测试过的输入上失败。用空值、零、缺失值和非常大的输入来测试,并明确地检查或处理这些情况。
LeetCode 上的 Runtime Error 是什么意思?
None 值,或者递归太深导致栈溢出。把结果页面上显示的失败输入拿来自己运行一遍,并检查边界情况:空数组、只有一个元素,以及允许的最大规模。运行时错误和异常是一回事吗?
RuntimeException 还是某一类异常的名字,也就是 NullPointerException 这类非受检异常。编译器能发现运行时错误吗?
只能发现一部分。编译器或 mypy 这样的类型检查器可以证明某些错误不可能发生,比如把文本和数字相加。但它无法知道程序运行时才会传入的值,比如用户输入的一个数字恰好是零。这类错误只能通过运行代码来发现,或者通过检查输入来处理。