深色模式
第 12 章 · 报错急救手册与调试
本章目标
遇到报错不慌:会读、会查、会自己定位问题。
12.1 排查四步法
- 读最后一行:错误类型 + 原因(这一行信息量最大)
- 往上找行号:报错发生在哪个文件的第几行
- 看那一行的上下文:变量是什么类型?是不是
None?拼写对不对? - 缩小范围:把可疑代码单独拿出来,用
print打印中间结果
一句经验:90% 的报错和你以为的地方不是同一个地方 —— 报错在 A 行,问题往往在 A 行之前。
12.2 高频报错对症下药
SyntaxError: invalid syntax
python
print("hi" # ❌ 少了右括号
if x == 1 # ❌ 少了冒号检查:括号引号成对、冒号、中英文标点(, vs , 是重灾区)。
IndentationError: unexpected indent
缩进不一致:同一层代码必须空格数相同,别混用 Tab 和空格。编辑器里开启"Tab 转 4 空格"。
NameError: name 'x' is not defined
变量名拼错,或者用了还没赋值的变量。
TypeError: can only concatenate str (not "int") to str
python
age = input("年龄:")
print("明年 " + age + 1) # ❌ 字符串 + 数字
print(f"明年 {int(age) + 1}") # ✅ValueError: invalid literal for int() with base 10: 'abc'
int() 收到了不能转的字符串。转换前用 .isdigit() 判断,或用 try 接住。
KeyError: 'phone'
字典没有这个键。改用 user.get("phone", "未填"),或先 if "phone" in user。
IndexError: list index out of range
下标越界。检查 len(lst),注意下标从 0 开始。
AttributeError: 'str' object has no attribute 'append'
用错了方法(字符串没有 append)。用 += 拼字符串,或改用列表。
ModuleNotFoundError: No module named 'requests'
没装 / 装到了别的环境。激活虚拟环境后 python -m pip install requests。
UnboundLocalError: cannot access local variable 'x'
函数里既想读又想改全局变量,忘了写 global x。
FileNotFoundError / UnicodeDecodeError
路径不对 / 编码不对 —— 见第 07 章。
12.3 三种调试手段
① print 大法(最朴素最有效)
python
def calc(items):
print("DEBUG 传入:", items, type(items)) # 看输入
total = sum(items)
print("DEBUG 合计:", total) # 看中间结果
return total / len(items)② assert 断言(给"我认为一定成立"的假设上保险)
python
def average(nums):
assert len(nums) > 0, "列表不能为空"
return sum(nums) / len(nums)假设不成立就立刻报错,比让错误数据往下跑要好得多。
③ 断点调试 breakpoint()
python
def buggy(data):
breakpoint() # 程序在这里暂停,进入调试器
return data["value"] * 2运行到这一行会停下,可以看变量、单步执行。VS Code 里更直观:行号左边点一下打红点,按 F5 启动调试。
调试器常用命令(终端里):p 变量名 查看值、n 下一行、c 继续、q 退出。
12.4 常见错误模式与成因
| 现象 | 常见成因 | 定位方法 |
|---|---|---|
| 报错行看起来没问题 | 错误源自前面几行的变量或类型 | 从报错行往前逐行检查变量与类型 |
| 改了代码但结果没变 | 文件未保存,或运行的另一个文件 | 确认保存路径与运行命令一致 |
| 结果时对时错 | 字符串与数字混用;可变对象共享 | print(type(x));检查默认参数与类属性 |
| Traceback 很长 | 只需末行错误类型与触发位置 | 看最后一行 + 对应文件行号 |
| 循环越来越慢 | 循环内重复构造大对象或反复 IO | 把不随循环变化的部分移到循环外 |
12.5 附:"写成什么样才会报这个错"速查
上面每条已给了成因;这里把最常撞的几种,用 2 行代码直接演示"错误写法 → 正确写法":
python
d = {"a": 1}
# KeyError: print(d["b"]) → print(d.get("b")) 或 if "b" in d
# IndexError: print([1, 2][5]) → 先 len() 判断或改用 for 遍历
# ValueError: print(int("abc")) → if s.isdigit(): int(s)
# TypeError: print("18" + 1) → print(int("18") + 1)
# NameError: print(totl) → 变量名拼写/是否已赋值
# AttributeError: "abc".push("d") → 查清方法名:"abc".upper()
# ModuleNotFoundError:import pandas(未装) → python -m pip install pandas(已激活 venv)
# FileNotFoundError:open("不存在.txt") → 用 Path(__file__).parent 拼绝对路径
# ZeroDivisionError: 100 / 0 → 计算前 if b != 0:
count = 0
def f():
count += 1 # ❌ UnboundLocalError:函数里改外部变量需先写 global count
# (或把赋值改成 count = 1,那就是局部变量了)以及两类"最难自己发现"的:
python
# ① 缩进错误:同一层代码必须对齐
if True:
print("A")
print("B") # ❌ IndentationError: unexpected indent
# ② 中文标点:看起来一样,机器不认
# print("你好") ❌ 引号是中文的
# print("你好") ✅ 英文引号12.6 练一练
- 下面这段代码有 3 个错误,找出来并修好(改完应该输出 80.0):
python
def get_avg(scores)
total = 0
for s in scores:
total = total + s
return total / len(scores)
print(get_avg([90, 80, 70)- 故意写一段会报
KeyError的代码,用try/except处理掉。 - 用
breakpoint()或 VS Code 断点,观察一个循环里变量的变化过程。
本章关键词
Traceback、错误类型对照、print 调试、assert、breakpoint()、VS Code 调试