Skip to content

异常信息与定位 ​

学习层次

读懂 Traceback、识别异常类型和定位出错行属于核心掌握。它们是后续标准库练习和独立排错的前置能力。

程序出错时,Python 会给出一份 Traceback。面对一大段报错信息,如何判断错误类型、找到出错代码,并确定下一步检查什么?本章先建立统一的阅读顺序,再用常见异常练习定位方法。

不需要背下所有异常名称,重点是读出报错提供的线索,并知道常见异常应该先检查什么。

异常定义 ​

程序执行到无法继续处理的状态时,Python 如何说明原因?先从最小示例认识异常对象和 Traceback 的基本信息。

程序执行过程中遇到无法继续处理的问题时,会抛出异常。如果异常没有被处理,程序就会停止,并输出 Traceback。

例如,除数为 0 时会抛出 ZeroDivisionError:

python
>>> 1 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

最后一行包含两部分:

  • ZeroDivisionError:异常类型。
  • division by zero:错误说明。

异常类型帮助我们判断问题属于哪一类,错误说明则会补充这一次出错的具体原因。

Traceback 的阅读顺序

Traceback 结构 ​

Traceback 可以理解为程序出错前留下的调用记录。排查时按下面的顺序读取:

  1. 看最后一行,确认异常类型和错误说明。
  2. 从下往上看调用位置,先找最接近异常的代码。
  3. 根据文件名和行号回到自己的代码。
  4. 检查这一行用到的变量和前面的执行过程。

单层调用定位 ​

最简单的报错只有一个代码位置:

python
>>> 1 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

可以这样读:

  1. 最后一行说明执行除法时除数为 0。
  2. 上一行说明问题出现在当前输入的第 1 行。
  3. 回到 1 / 0,检查除数为什么会得到 0。

多层调用定位 ​

程序经过多层函数调用后,Traceback 会列出完整的调用过程:

python
def calculate_average(total, count):
    return total / count


def show_average(total, count):
    print(calculate_average(total, count))


show_average(100, 0)

运行结果类似下面这样:

text
Traceback (most recent call last):
  File "main.py", line 9, in <module>
    show_average(100, 0)
  File "main.py", line 6, in show_average
    print(calculate_average(total, count))
  File "main.py", line 2, in calculate_average
    return total / count
ZeroDivisionError: division by zero

这段信息说明:

  1. 程序从 show_average(100, 0) 开始调用。
  2. show_average() 又调用了 calculate_average()。
  3. 真正抛出异常的是 return total / count。
  4. 此时传入的 count 是 0。

排查多层调用时,不要只停在最外层的调用代码。先找到最接近异常的位置,再沿调用过程检查错误数据从哪里传进来。

常见异常类型 ​

当最后一行给出异常类型后,下一步应该检查什么?下面按基础练习中常见的异常类型,结合最小示例整理排查方向。

NameError ​

访问了一个没有定义的名称:

python
>>> student_name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'student_name' is not defined

优先检查变量是否已经定义,以及名称有没有写错。

TypeError ​

当前数据类型不支持这次操作:

python
>>> "年龄:" + 18
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str

优先检查参与运算的数据类型,以及函数收到的参数类型。

ValueError ​

数据类型可以接收,但具体的值不符合要求:

python
>>> int("abc")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'abc'

int() 可以接收字符串,但 "abc" 不是有效的整数内容。

ZeroDivisionError ​

执行除法时,除数的结果为 0:

python
>>> 1 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

看到这个异常,要继续检查除数为什么会变成 0,不能只检查代码里有没有直接写出数字 0。

IndexError ​

序列索引超出范围:

python
>>> scores = [90, 85, 92]
>>> scores[3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

列表只有 3 个元素,有效索引是 0、1、2。看到这个异常,优先检查序列长度和索引值。

KeyError ​

访问了字典中不存在的键:

python
>>> server = {"host": "127.0.0.1", "port": 80}
>>> server["name"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'name'

优先检查键名有没有写错,以及这个键是否一定存在。键可能不存在时,可以根据需求使用 get()。

FileNotFoundError ​

要读取的文件不存在:

python
>>> open("students.json", encoding="utf-8")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'students.json'

优先检查文件名、文件路径和程序当前的工作目录。

AttributeError ​

访问了对象不存在的属性或方法:

python
>>> name = "Python"
>>> name.age
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'age'

优先检查属性名,以及当前变量保存的究竟是哪一种对象。

SyntaxError ​

代码不符合 Python 语法:

python
>>> if score >= 60
  File "<stdin>", line 1
    if score >= 60
                  ^
SyntaxError: expected ':'

SyntaxError 通常发生在程序正式执行前。箭头会尽量标出解释器发现问题的位置,但真正缺失或多余的内容也可能在它附近。

常见原因包括:

  • 括号或引号没有配对。
  • if、for、while、def 等语句末尾缺少冒号。
  • 关键字或表达式没有写完整。

异常定位流程 ​

再次遇到异常时,可以按这套流程把报错线索落实到具体代码和运行数据:

  1. 重新运行一次,确认问题能够稳定出现。
  2. 保留完整 Traceback,不要只截取最后一句。
  3. 从最后一行确认异常类型和错误说明。
  4. 根据文件名和行号找到自己的代码。
  5. 检查这一行用到的数据,以及数据从哪里传来。
  6. 修改后再次运行,确认原来的操作已经恢复正常。

常见异常可以提供排查方向,但异常名称不会直接告诉你最终修改方案。例如 ZeroDivisionError 说明除数为 0,至于应该修改数据、调整执行顺序,还是增加边界处理,还要结合程序需求判断。

从报错到定位

小结 ​

本节重点掌握三件事:

  1. Traceback 包含异常类型、错误说明、文件位置和调用过程。
  2. 多层调用出错时,先从最接近异常的位置开始检查。
  3. 异常类型提供排查方向,最终原因仍要回到代码和运行数据中确认。

下一节继续解决:哪些异常应该处理,以及怎样用 try...except 让程序作出合适的响应。

练习 ​

  1. 分别制造一个 NameError、TypeError 和 IndexError,观察最后一行有什么不同。
  2. 把 show_average(100, 0) 改成可以正常运行的调用,再比较两次结果。
  3. 找一段以前出现过的完整 Traceback,按“异常类型、错误说明、出错位置、调用过程”重新读一遍。