异常与资源管理
异常与资源管理 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。
学习目标
这一课解决两个必然发生的问题:文件不存在/内容损坏怎么办,文件读一半崩了谁来关。目标是写出「错误信息有用、资源必定释放」的代码,并且不吞异常。
问题场景
P06 要做的校验工具会遍历几十个 JSON 文件:有的不存在、有的被手改坏了、有的编码不对。裸跑第一版大概长这样:
f = open(path)
data = json.load(f) # 文件不存在?内容是坏的?全抛异常直接崩
JS 里你写过 try/catch 加 finally,Python 的结构几乎一样,但多一个关键设施:with 语句,它把「必定关闭」从纪律变成语言机制。
核心解释
异常处理的原则按顺序就三条:只捕获能处理的、错误信息要保留上下文、资源交给 with。
import json
def load_records(path: str) -> list:
try:
with open(path, encoding="utf-8") as f:
return json.load(f)
except FileNotFoundError:
print(f"跳过:文件不存在 {path}")
return []
except json.JSONDecodeError as e:
raise ValueError(f"课程文件损坏: {path} 第{e.lineno}行") from e
三个要点逐个说清:
- except 要写具体类型。
except Exception:或裸except:会把拼写错误、逻辑 bug 一起吞掉,你只会看到莫名其妙的「没输出」。只捕获你确实能处理的那一两种。 raise ... from e保留异常链。转成业务异常时把原始异常挂上去,日志里能看到完整因果链;直接raise ValueError(...)会丢掉「第几行」这类原始信息。- with 等价于 JS 的
using/try-finally组合。块内无论正常返回还是抛异常,f.close()必定执行。自己写资源管理时用contextlib.contextmanager达到同样效果。
文件之外,sqlite3.connect()、socket 同样适用 with。P11 写数据库、P18 看日志时,这套结构会反复出现。
示例拆解
用 P03 的模块结构验证异常路径:
# main.py
from parsing import load_records
if __name__ == "__main__":
print(load_records("not-exist.json")) # 跳过:文件不存在 ... → []
try:
load_records("broken.json") # 内容是 {bad json
except ValueError as e:
print("捕获:", e) # 捕获: 课程文件损坏: broken.json 第1行
预期行为:缺文件返回空列表并提示(可恢复,程序继续跑);坏文件抛出带路径和行号的业务异常(不可静默,调用方必须知道)。这个「可恢复的记下来继续、不可恢复的带上下文抛出去」的分界线,就是判断一段异常处理写没写对的唯一标准。
动手任务
本课实验区有可直接运行的版本(纯标准库):
- 给
load_records补上PermissionError分支,处理无权限文件,返回空列表并打印原因。 - 用
contextlib.contextmanager写一个open_quiet(path)上下文管理器:进入返回文件对象,退出自动关闭并打印「closed」。 - 把某个
except改成裸except: pass,制造一个拼写错误感受「异常被吞」的排查难度,然后改回来。
常见错误
except: pass静默吞掉:出错了但程序「看起来正常」,最难的 bug 都这么来的;至少要打印或记日志。- 捕获范围过大:
except Exception把 KeyboardInterrupt 之外的全接住,调试信息全没了;写具体异常类型。 - 在 except 里 return 掩盖问题:本该让上层知道的失败被一个默认值盖掉;先想清楚这个失败谁能处理。
- 手动 close 不用 with:异常路径上必漏;资源一律 with,自己包装就用 contextmanager。
检查与复盘
自查清单:
- 代码里找不到裸
except:和except: pass - 能说清 FileNotFoundError 和 JSONDecodeError 分别该恢复还是该抛
- 打开过的每个资源都由 with 管理而不是手动 close
参考资料
- Python 官方教程:错误与异常 —— try/except/finally 与异常链
- contextlib 标准库文档 —— 自定义上下文管理器
读完这一课了?
标记完成后,工作台会安排接下来的学习。