Python for AI

模块 4 - 实用 Python · 第 16 课

异常与 Debugging

读懂 traceback,用 try/except 处理可预期输入问题,并用最小实验定位错误。

学习目标

  • 区分 SyntaxError、NameError、TypeError、ValueError 和 KeyError 等常见异常;
  • 从 traceback 找到异常类型、文件和行号;
  • 只捕获能够处理的异常;
  • 用最小可复现示例(minimal reproducible example)调试数据处理代码。

先读 traceback 的最后一行

values = [1, 2]
print(values[5])

最后一行会指出 IndexError;向上查找到自己的代码行,再检查索引、类型和输入。一次只改一个假设,保留能重现问题的最小示例。

异常类型提供线索

print(missing_name)       # NameError
int("3.5")                # ValueError
{"a": 1}["b"]            # KeyError

SyntaxError 通常在代码运行前发现;TypeError 表示操作数类型不适合;ValueError 表示类型对了但值不合法。错误名称不是噪声,而是排查方向。

处理可预期输入

def parse_batch_size(text):
    try:
        value = int(text)
    except ValueError:
        return None
    return value if value > 0 else None

print(parse_batch_size("64"))
print(parse_batch_size("unknown"))

这里只捕获 ValueError,因为我们知道转换失败是可以处理的情况。不要使用空的 except: 把真正的程序错误吞掉;必要时用 raise 重新抛出并保留上下文。条件表达式只是这里的简短写法,读不懂时可以展开成 if/else。

调试 JSON 配置

import json
from pathlib import Path

def load_batch_size(path: Path) -> int:
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
        value = int(data["batch_size"])
    except FileNotFoundError as error:
        raise RuntimeError(f"配置文件不存在:{path}") from error
    except (KeyError, ValueError, json.JSONDecodeError) as error:
        raise RuntimeError("配置缺少有效的 batch_size") from error
    if value <= 0:
        raise ValueError("batch_size must be positive")
    return value

这是一个可独立复制的函数示例。它把底层异常转换为更接近业务含义的错误,但没有隐藏原因:from error 保留了原始 traceback。

AI 调试顺序

遇到训练异常时,按顺序检查:输入文件和配置、batch 的 shape、Tensor 的 dtype/device、再检查模型计算。打印少量样本和中间 shape,通常比一次添加大量日志更有效。

练习

★ 基础

为 parse_batch_size 增加空字符串、"0" 和 "32" 的测试,写出预期结果。

★★ 应用

写一个函数从字典读取 learning_rate,捕获缺失键和非法数值,并返回可读的错误信息。

★★★ Debugging challenge

下面的函数有两个问题。先预测异常,再修复并用 assert 验证:

def mean_loss(values):
    return sum(values) / len(value)
完整参考答案 ```python def mean_loss(values): if not values: raise ValueError("values must not be empty") return sum(values) / len(values) assert mean_loss([1.0, 3.0]) == 2.0 try: mean_loss([]) except ValueError: pass else: raise AssertionError("empty input should fail") ``` 原代码把参数名 `values` 错写成 `value`,会产生 `NameError`;空列表还会产生除零错误,因此函数需要输入边界检查。

小结与速查表

先读 traceback 最后一行,再定位代码行;用异常类型判断排查方向;只捕获可处理的异常;用 assert 固定预期;用最小示例隔离 shape、dtype、路径和配置问题。

D2L 衔接

D2L 调试不只是修语法:你还要判断数据 batch 是否为空、shape 是否兼容、dtype/device 是否一致。掌握 traceback 和最小示例后,遇到训练错误时能更快找到真正的边界。

第 16 课 学习进度仅保存在当前浏览器。