Week 3 学习成果|异常、traceback 与 Debug 起步
Week 3 的实际产出:Day 1 异常与 traceback 训练,能读 traceback、区分调用帧与抛出点、解释 KeyError / AttributeError / TypeError / ZeroDivisionError 的成因,并用 .get() 修复 KeyError。
本篇对应 Week 3 学习计划,与一年学习计划总纲 Phase I 的 Week 3 · 异常、测试与 Debugging(等级 L2)一致,按总纲 Part II「每周固定执行模板」编排。计划篇保留任务与要求,这里放实际做出来的东西和训练记录。目前有书面成果的是 Day 1,Day 2–5 完成后再补进来。
🎯 本周目标
L1
- ✅ 能读懂 traceback,讲清 Exception / traceback / raise / try-except-finally 的语义
L2
- 🟡 三类测试(boundary / invalid input / exception)与 fixture / mock 尚未产出书面成果
L3
- 总纲本周不设 L3
📚 Core Knowledge
- 异常是什么、异常对象与 traceback 的结构
- traceback 的读法:从下往上读,区分调用帧与抛出点,过滤库帧
raise主动抛异常与异常链raise ... from ...- try / except / else / finally 的执行顺序
- LBYL 与
.get()两种修 bug 的字典写法 - 四类常见异常的成因:KeyError / AttributeError / TypeError / ZeroDivisionError
✍️ Human Core
- 读 4 个 traceback,能说出异常类型、消息、抛出位置
- 区分“调用帧”和“抛出点”
- 能解释 KeyError / AttributeError / TypeError / ZeroDivisionError 的成因
- 能修复 KeyError,用
.get()替代直接索引 - boundary test / invalid input test / exception test(Day 2)
🤖 AI Build
- AI 扩充测试、review 测试、人为制造 bug(Day 4–5)
🧪 Experiment
Hypothesis
- 反复读 traceback 并归纳异常成因,能建立“从异常类型反推根因”的直觉。
Experiment
- Day 1 读 4 个 traceback,逐条拆出异常类型、消息、抛出位置,并对比调用帧与抛出点。
Result
- 4 个 traceback 均能定位异常类型与抛出点;能解释 KeyError / AttributeError / TypeError / ZeroDivisionError 的成因;KeyError 用
.get()修复。
Conclusion
- 读 traceback 的关键是“从下往上 + 只看自己写的帧”;traceback 只给事实(类型 / 消息 / 位置),不给原因和修法,这两步得自己判断。
📝 数智工程师考试映射
- 异常处理与错误传播
- traceback 阅读与根因定位
✅ Acceptance
L1
- 能读懂 traceback,定位到出错文件与行号
- 能区分“调用帧”和“抛出点”
L2
- 能独立编写 boundary / invalid input / exception test(Day 2)
- 能按要求完成 Debug 四步法(Day 4)
L3
- 总纲本周不设 L3
🧠 本周最重要的问题
看到 traceback 后,能不能不靠猜,走完「定位 → 解释 → 原因 → 修复」四步?
❓ 尚未解决
- Day 2–5 的三类测试、fixture / mock、四类 bug 实验尚未产出书面成果
📊 Final Level
L2(进行中)
Day 1 成果|异常、traceback 与 Debug 起步
对应计划:Day 1|异常 + traceback 复习 + 读 traceback 训练
异常是什么
程序做不到某件事时,抛出异常对象。没人接住,程序中断并打印 traceback。
读 traceback
Traceback (most recent call last):
File "demo.py", line 10, in <module> ← 最早发生
result = parse("abc")
File "demo.py", line 5, in parse ← 最近发生(抛出点)
return int(s)
ValueError: invalid literal for int() ... ← 异常类型 + 消息
读法:
- 从下往上读
- 最下面:异常类型和消息
- 往上找:哪一行抛的(最靠近异常类型的那一帧)
- 再往上:谁调用了谁
- 找“自己写的代码”
traceback 里混着标准库 / 第三方库的帧:找自己项目的文件名,跳过库的帧。
traceback 不告诉你的事:
- 为什么这行会出错
- 是数据问题还是代码问题
- 怎么修
这三件事得自己判断。
raise 主动抛异常
raise ValueError("年龄不能为负数")
常见用途:参数校验、不支持输入、记录后重抛。
异常链 raise ... from ...
try:
int("abc")
except ValueError as e:
raise RuntimeError("配置解析失败") from e
- 对外暴露
RuntimeError ValueError保留在 traceback 里当根因- 用于分层转换:底层技术错误 → 上层业务错误
try / except / finally 执行顺序
| 情况 | 顺序 |
|---|---|
| 成功 | try → else → finally |
| 失败被捕获 | try → except → finally |
| 失败没捕获 | try → finally,异常继续抛 |
finally 里的 return 会覆盖 try 里的 return。
修 bug 的两种字典写法
LBYL:先检查
def get_user(users, user_id):
if user_id not in users:
return None
return users[user_id]
.get():字典内置,最简洁
def get_user(users, user_id):
return users.get(user_id)
.get(key, default) 规则:
- 键存在 → 返回真实值
- 键不存在 → 返回 default(不写则 None)
- 永不抛 KeyError
Debug 四步法
1. 定位:哪一行?哪个文件?
2. 解释:这行在干什么?为什么出错?
3. 原因:根本原因是什么?
4. 修复:改什么?怎么验证改对了?
今日训练完成
- 读了 4 个 traceback,能说出异常类型、消息、抛出位置
- 区分了“调用帧”和“抛出点”
- 能解释 KeyError / AttributeError / TypeError / ZeroDivisionError 的成因
- 能修复 KeyError,用
.get()替代直接索引
来源与延伸阅读
- 01Week 1 学习计划|Python 对象模型与数据结构
- 02一年学习计划:从 Python 到 Data/AI 系统的 52 周
- 03Week 1 学习成果|复杂度实测、对象模型与数据结构实战
- 04Week 2 学习计划|Python 函数、作用域、闭包与模块化
- 05Week 2 学习成果|闭包、decorator 与工程化重构
- 06Week 3 学习计划|异常、测试与 Debugging
- 07Week 3 学习成果|异常、traceback 与 Debug 起步
- 08Week 4 学习成果|Big-O 与四类基础算法
- 09Week 5 学习成果|Stack、Queue 与 MinHeap
- 10Week 6 学习成果|图算法与 Python Engineering Toolkit