函数、输入边界与异常
- 理解参数、返回值与函数调用
- 为外部输入设置简单明确的校验
把一段规则命名
晨光书架要在不同地方计算阅读分钟合计。如果每处都复制循环,修改规则时容易漏掉某一处。函数是给一段处理逻辑命名,让它接收输入并返回结果。参数是函数接收的数据,返回值是它交回给调用者的结果。不是所有短代码都必须包装成函数;当一段逻辑需要单独测试、复用或说明清楚时,函数才真正有帮助。这里建立一个total_minutes函数,只做一件事:计算合法分钟列表的总和。
输入边界为何需要校验
课程里的数据由我们控制,但真实文件或手工输入可能含文本、负数或空项。系统边界是数据从外部进入程序的位置,应检查必要条件。当前规则要求每项是非负整数,空列表允许且合计为零。负分钟没有任务意义,文本十二也不能悄悄当作整数处理。校验要符合任务,不是为了显得安全就接受所有类型并复杂转换。Python中布尔值与整数有特殊关系,本例用type(item) is int明确只收普通整数,避免把真假值误计为分钟。
完整函数示例
def total_minutes(values):
total = 0
for item in values:
if type(item) is not int or item < 0:
raise ValueError("分钟必须是非负整数")
total += item
return total
result = total_minutes([5, 12, 8])
print(result)- 第一行定义函数,values是输入参数,此时不会立即计算示例数据。
- 第二行把局部合计设为零。
- 第三行依次遍历传入的各项。
- 第四行检查类型不合法或小于零,任一条件成立都进入错误分支。
- 第五行抛出值错误,停止当前计算并说明输入要求。
- 第六行把当前合法分钟数加到合计中。
- 第七行在循环完成后返回合计,不只是显示它。
- 第八行用五、十二、八调用函数,把返回结果保存为result。
- 第九行显示二十五这个结果。
返回与显示不要混淆
return把结果交回调用者,print把内容显示出来。一个函数只有print而没有相应return,调用方不一定拿到想要的数据。此例把计算与显示分开,后续可以用返回值做比较或测试,不必从屏幕文字里提取数字。函数内的total属于这次调用的局部状态,下次调用从零开始,不会自动把上次结果累加。手工推演时可以把每次调用画成一个独立小框,理解参数进入、结果返回的方向。
异常是清楚报告边界
输入含负数时,程序按规则报告ValueError,不应该把负数忽略并假装完整统计。实际使用时可以在最外层按需要捕获已知异常并提示修订输入,不要笼统吞掉所有错误。课程示例不使用执行任意文本的功能、不调用系统命令,外部数据只能作为值处理。这样函数既方便测试,也让合法输入和拒绝条件明确;正确程序并不保证所有输入都能成功,而是合法时算对、不合法时清楚停止。
本节要点
- 函数用参数接收输入,用返回值交回结果
- 外部输入校验应基于明确任务规则
- 异常不应被吞掉或伪装成成功
动手练习:测试函数的正常、空与错误输入
- 预测total_minutes调用五、十二、八的结果
- 预测空列表结果,并解释为什么从零开始
- 分别用负一和文本十二构造错误输入,说明预期异常
自查清单
- 正常与空输入结果正确
- 非法输入被明确拒绝而非静默忽略
先自己做,再查看参考答案
正常列表五、十二、八的返回值是二十五;空列表不进入循环,局部合计仍为零,因此返回零。列表含负一时类型虽是整数,但小于零,函数抛出ValueError;列表含文本十二时类型不是普通整数,也抛出同样异常。这里不是让函数尽量猜测输入意图,而是坚持明确的数据协议。返回值与显示不同,函数先把数字交回result,print才显示它。每次调用重新把total设为零,所以不同调用互不累积。异常输入的预期应记录为清楚拒绝,不是零或部分合计;否则调用者可能把不完整数据误当成成功统计。