本篇是《Python 从入门到初级》第 9 / 20 篇。示例使用 Python 3.12 兼容语法,完整目录结构与数据见配套源码包。
报错是程序提供的线索。它可以指出语法写错、数据不能转换、文件不存在或规则不满足。本篇学习读 traceback,并在该处理的边界捕获异常。

1. 先分清语法错误和运行异常
缺冒号、括号不配对等问题,可能在程序真正运行前就被解析器拒绝。SyntaxError 的箭头和行号是查找入口,错误原因有时也在前一行。
运行异常则发生在程序执行期间,例如 int("abc") 的 ValueError、读取不存在字典键的 KeyError。Traceback 展示调用路径,最后一行通常给出异常类型和消息。
不要只复制最后一句去搜索:同时看自己的文件名、行号,以及当时处理的输入。说明见 错误与异常教程。
2. 完整示例:验证端口配置值
保存为 lesson09.py:
def parse_port(text):
try:
port = int(text)
except ValueError as exc:
raise ValueError("端口必须是整数") from exc
if not 1 <= port <= 65535:
raise ValueError("端口必须在 1 到 65535 之间")
return port
success = 0
failed = 0
for raw in ["8080", "abc", "70000", "443"]:
try:
port = parse_port(raw)
except ValueError as exc:
failed += 1
print(f"拒绝 {raw!r}:{exc}")
else:
success += 1
print("可用的配置值:", port)
print(f"格式检查通过 {success} 项,失败 {failed} 项")
预期 8080、443 通过格式与范围检查;abc 因不是整数被拒绝,70000 因超出范围被拒绝。总计通过两项、失败两项。
这里只验证配置值的形式,不会检查端口是否监听、是否被占用或是否能联网。名字和提示都应与实际检查能力一致。
3. 哪段代码值得放进 try
parse_port 内只把可能转换失败的 int(text) 放进 try。捕获 ValueError 后,补充适合当前业务的错误说明,再用 raise ... from exc 保留原始原因。
外层循环决定:一项失败后记录并处理下一项。这是一个明确的策略;如果是必须全部有效才能启动的配置,就可能应该立即停止。
try 的范围过大时,很容易把本不想忽略的编程错误也包进去。先问“我具体准备怎样处理哪一种失败”,再选择异常类型。
4. except、else、finally 各做什么
except 处理匹配异常;else 在 try 没有抛出异常时执行;finally 用于无论正常还是异常都需要执行的收尾工作。
文件操作通常优先使用 with 管理资源,第 10 篇会展示。数据库连接也需要正确关闭,不能仅因为“没有写报错”就假定资源已经释放。
不要使用一个无条件的 except 把所有错误都变成“跳过”。尤其不要一边失败一边输出“全部完成”,让外部任务误以为成功。
5. 调试时可以怎样缩小问题
先减少输入,只保留能复现问题的最小记录。查看 repr(value) 和 type(value),确认有没有空白、换行和类型误解。
当代码较多时,可以在自己的文件中使用 breakpoint(),在调试器里检查变量后逐步运行。它会暂停等待交互,不适合直接留在无人值守的定时任务中。
还要区分“没有异常”和“结果正确”:金额少算了一个状态,通常不会自动抛异常,要靠固定数据和测试发现。
6. 练习与参考结果
向输入列表增加 "0"、"65535"、" 22 "。预期 0 被拒绝,65535 通过,带两端空格的 22 也会被 int 接受。
如果业务要求“输入里不能有任何空格”,需要增加这条规则;不能把转换函数默认接受的格式误认为你的业务已经决定接受。