Skip to content

Python 错误与异常处理 ​

先读异常类型 ​

语法错误通常在执行前被解析器发现;运行中的失败按具体异常类型区分。RuntimeError 不是所有运行错误的统称。

异常常见触发
ValueErrorint("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继续传播,不能统称“文件不存在”。这些是待验证预期,本轮未读写练习文件。

继续阅读