← 返回周历 预备 视频 DeepInfer 101
预备 1

预备 1:用最小复现修复最大值

浏览文字约 3 分钟 · 手算与练习请按正文分段完成 源文件:Markdown 本地渲染版 · 无需联网
本页目录 · 5 节

目标:从错误结果定位到一个具体的错误假设。
修改:prep.py 中的 maximum。
预计投入:30–60 分钟。

1. 先写规格

本节路线:以全负数和空列表分别检查逻辑与边界,修复prep q1;先修为预备0的traceback阅读。命令沿用 课程根目录。离开本节要解释best在每轮代表什么,并设计一个不在正文中的失败反例,不能只把初值改完就结束。

maximum(values) 对非空数值列表返回最大元素,不修改输入;空列表抛 ValueError。本题不用 max(),因为我们要观察循环中的状态。

输入 [2, 7, 3]   → 7
输入 [-5, -2, -9] → -2
输入 [-8]         → -8
输入 []           → ValueError

raise ValueError("列表不能为空") 的意思是拒绝没有定义答案的输入。本题不约定空列表的最大值为 0。

2. 先跟踪错误,不急着改

starter 的核心是:

best = 0
for value in values:
    if value > best:
        best = value

用 [-5, -2, -9] 跟踪:

本轮 value比较前 bestvalue 大于 best?比较后 best
-50否0
-20否0
-90否0

程序没报异常,却返回了不在输入中的 0。这是逻辑错误。继续把输入缩成 [-8],错误仍然存在;这就是一个更小的复现。

3. 用不变式决定怎样修

我们希望每轮结束后都成立:

best 是“已经看过的元素”中的最大值。

因此开始比较前,best 应有一个来自已看元素的合法值。不要改成 -100000:输入可能更小;也不要只判断某个测试列表。

先在 maximum 中处理空输入,再决定非空时的初值。你可以从第二个元素继续循环,也可以重新比较第一个元素;两种都可以得到正确答案。

4. 动手和逐层提示

只改 maximum。每次改完运行:

python course/tools/grade.py prep --question q1 --failfast
提示 1:应该改变哪个假设?

原函数假定最大值至少为 0,但题目没有这个条件。

提示 2:如何得到一个合法初值?

非空列表里,第一个元素一定存在;先看过它,手中就有一个“已经看过部分”的最大值。

提示 3:局部伪代码
如果列表为空:拒绝输入
best = 第一个元素
遍历其余元素:比 best 大时更新
返回 best

5. 给自己的修复找反例

测试通过后,再自己预测并检查 [-1000000, -1000001]、[4, 4, 4]、[0, -1]。你可以临时加打印,也可以在实验目录用 Python 交互窗口调用函数;提交前移除临时打印即可。

记录:错误假设是什么?哪个最小输入推翻了它?修复为什么适用于没见过的输入?

下一步:预备 2:列表和矩阵。