学习目标:读写列表中的字典,跟踪循环中的累计值,解释空列表的结果。
前置:第 02 课的变量、整数和判断。预计 55 分钟。
本课交付:一张循环追踪表和增加第 4 条记录后的输出。
一天可能学习 Python 25 分钟、阅读 15 分钟,又学 Python 20 分钟。如果定义 minutes1、minutes2、minutes3,第 4 次学习就得再修改程序结构。
用列表保存“有顺序的一组记录”,每条记录再用字典说明各个值的含义。之后循环处理每条记录,无论有 3 条还是 30 条,规则相同。
records = [
{"subject": "Python", "minutes": 25},
{"subject": "阅读", "minutes": 15},
{"subject": "Python", "minutes": 20},
]
外层 [] 是列表,里面有三个元素,用逗号隔开。内层 {} 是字典,"subject" 和 "minutes" 是键,后面是对应的值。
records[0] 取第一个元素,Python 的索引从 0 开始;records[0]["minutes"] 再从这个字典取分钟数,得到 25。索引回答“第几个”,字典键回答“哪个字段”。
运行 py -3 versions/03_records.py。数据后面的处理代码是:
total = 0
for record in records:
total = total + record["minutes"]
print(f"加上 {record['minutes']},累计 {total}")
print(f"记录数:{len(records)}")
print(f"总分钟:{total}")
预期:
加上 25,累计 25
加上 15,累计 40
加上 20,累计 60
记录数:3
总分钟:60
for record in records 每轮让名字 record 指向下一条字典。len(records) 返回元素数量,并不把每条记录的字段也算进去。
| 轮次 | 当前 minutes | 执行前 total | 执行后 total |
|---|---|---|---|
| 第 1 轮 | 25 | 0 | 25 |
| 第 2 轮 | 15 | 25 | 40 |
| 第 3 轮 | 20 | 40 | 60 |
total = total + ... 先计算右侧,再把新结果赋回左侧。它不是数学等式,而是“用旧值计算新值”。
初始化 total = 0 必须在循环外。如果把它缩进循环,每轮都从 0 开始,最后只剩最后一条的 20。这个错误用上表就能解释,无需猜测。
在循环之前加:
records.append({"subject": "英语", "minutes": 10})
append 把一个元素加到列表末尾,之后输出应为 4 条、70 分钟。不是 records = records.append(...):这个方法直接修改列表,返回值是 None。
再临时把 records 改成 [],输出应是 0 条、0 分钟。循环一次也不执行,total 保留初值。这也是为什么初始化要在循环外。
| 现象 | 可能原因 | 检查方法 |
|---|---|---|
KeyError: 'minute' | 键名与数据不一致 | 打印当前 record 的全部内容 |
| 结果只有 20 | 每轮把 total 归零 | 看初始化的缩进位置 |
records 变成 None | 接收了 append 的返回值 | 直接调用 append,不重新赋值 |
IndexError | 请求了不存在的位置 | 三条记录的索引只有 0、1、2 |
在本课代码里增加一个 long_count,统计时长至少 20 分钟的记录数量。先用原始三条记录,预期是 2;再加入 10 分钟英语记录,预期仍然是 2。
提示:在循环外初始化计数器;在循环内检查当前记录;满足条件才加 1。请先写自己的实现,再看解释。
条件应为 record["minutes"] >= 20;满足时更新 long_count = long_count + 1,等于 20 的记录也必须计入。
验收同时保留三项:原始数据 3/60、增加一条后 4/70、空列表 0/0;解释为什么列表长度和 long_count 不总是相等。
如果另一个地方也要算总分钟数,复制循环会让修改变得重复。下一课将这段规则变成可调用的函数。