学习目标:给函数传入记录,接收返回的字典,区分 return 与 print,画出调用链。
前置:第 03 课的字典列表和循环。预计 50 分钟。
本课交付:正常数据与空数据两次函数调用,以及一张输入到输出的图。
上一课的统计写在脚本顶层。现在想同时统计“今天”和“昨天”,不能每次复制一整段循环再换变量名。把“怎样汇总”写成函数,把“汇总哪一批记录”当参数传入。
versions/04_functions.py 中的核心代码:
def summarize(records):
total = 0
for record in records:
total = total + record["minutes"]
return {"count": len(records), "total_minutes": total}
def 定义函数。records 是参数名,它在这次调用中指向传进来的值。定义函数时不会立刻执行循环;写出 summarize(...) 才是调用。
运行 py -3 versions/04_functions.py,预期:
记录数:3
总分钟:60
空记录: {'count': 0, 'total_minutes': 0}
先核对内容与数字。最后一行字典是 Python 的显示格式,通常带单引号,尚不是 JSON 文件。
main 准备 records
→ summarize(records) 计算
→ 返回 {count: 3, total_minutes: 60}
→ main 读取两个字段并 print
函数返回值赋给 result 后,可以用于显示,也可以参与下一步判断:result["total_minutes"] >= 60。
如果只在 summarize 里 print(total) 而不 return,调用者会收到 None,就无法正常按键取值。这就是“让人看见”和“把结果交给另一段代码”的区别。
假如函数不接收 records,而偷偷读取外面某个全局变量,同一条调用是否算今天还是昨天,就取决于那个变量最近被谁修改。
显式参数能让调用本身说明计算对象。函数每次用局部的 total = 0 开始,也不会把上一次调用的累计值带进来。
试着连续调用两次相同的列表,再调用空列表。预期前两次都是 60,第三次是 0。若第二次变成 120,检查是否误把 total 放到函数外并在多次调用之间复用了它。
文件末尾:
if __name__ == "__main__":
main()
直接运行这个文件时,Python 将 __name__ 设成 "__main__",于是调用 main。以后其他文件导入本文件时,这个条件不成立,可以取得 summarize 函数而不自动运行演示。
这里先理解“定义能力”和“启动程序”两种职责即可,不需要背下所有导入机制。07 课把函数放到独立模块,会再次用到它。
NoneType 相关错误:检查是否漏写 return,或把 print 的返回值当成了统计字典。增加一个独立函数 remaining_minutes(total, goal),返回还差的分钟数,最低为 0。
| 调用 | 预期返回 |
|---|---|
| remaining_minutes(25, 60) | 35 |
| remaining_minutes(60, 60) | 0 |
| remaining_minutes(75, 60) | 0 |
要求调用者自己决定怎样 print,函数里不打印。尝试用第二课 if/else 完成,不必急着寻找最短写法。
先算 goal - total,若结果小于 0 就返回 0,否则返回差值。
验收:给出三次返回值;解释 return 所在的缩进;手画 main → summarize → result → print,并指出循环在哪个节点发生。
汇总规则已独立,但记录仍写在 Python 文件里。下一课把数据移到 JSON,让使用者改记录时不必改程序。