Python 错误与异常处理
先读异常类型
语法错误通常在执行前被解析器发现;运行中的失败按具体异常类型区分。RuntimeError 不是所有运行错误的统称。
| 异常 | 常见触发 |
|---|---|
ValueError | int("abc") 等值不合法 |
TypeError | 不支持的类型操作或参数不匹配 |
NameError、IndexError、KeyError | 名称未定义、索引越界、字典键不存在 |
ZeroDivisionError | 除以零 |
FileNotFoundError、PermissionError | 文件不存在、权限不足,两者应区分 |
先查看 traceback 最后的异常和出错行,再沿调用栈寻找输入来源,不要直接把所有错误包进 except Exception。
捕获、else 与 finally
只捕获当前层能处理的异常,尽量缩小 try 范围。else 在 try 正常结束后执行,finally 在离开结构时执行清理。
python
def divide_ten(text):
try:
number = int(text)
result = 10 / number
except ValueError:
return "not an integer"
except ZeroDivisionError:
return "zero divisor"
else:
return result
assert divide_ten("2") == 5
assert divide_ten("x") == "not an integer"
assert divide_ten("0") == "zero divisor"文件资源的清理将在 下一课的 with中学习,通常不必手工写关闭文件的 finally。不要在 finally 里 return,它可能覆盖原返回值或异常。
主动抛出与传播
python
def positive_size(value):
if value <= 0:
raise ValueError("size must be positive")
return value
try:
positive_size(0)
except ValueError as error:
assert str(error) == "size must be positive"不能恢复的异常可直接向上传播;记录后重新抛出使用裸 raise,避免吞掉错误。包装为业务异常时可用 raise NewError(...) from error 保留原因链。
练习与资料
为一个读取 JSON 文件的函数区分“文件不存在”和“JSON 格式错误”,其他失败继续传播。参见 官方异常教程;下一步读 推导式、装饰器与资源管理。
参考解答
先缩小try范围,不把程序自身的TypeError也变成输入格式错误。下面函数约定失败时返回可区分的代码与None,成功时返回ok和解析值:
python
import json
from pathlib import Path
def read_json(path):
try:
text = Path(path).read_text(encoding="utf-8")
except FileNotFoundError:
return "missing_file", None
try:
return "ok", json.loads(text)
except json.JSONDecodeError:
return "invalid_json", None不存在路径预期missing_file,内容为 { 的文件预期invalid_json,内容为 null 则是 ("ok", None)。PermissionError和UnicodeDecodeError继续传播,不能统称“文件不存在”。这些是待验证预期,本轮未读写练习文件。
继续阅读
- 开发实践
- 排错
- 开发实践