
零基础入门python06把重复代码变成函数——商品结算器一、上一篇课后练习讲解成绩统计练习要求输出排名。参考做法是sorted(scores, reverseTrue)生成新列表不直接修改原始成绩如果要同时保留姓名和成绩应排序字典列表的score字段。可执行验收答案defrank_students(rows:list[dict])-list[dict]:返回新列表原始列表顺序和内容保持不变。returnsorted(rows,keylambdarow:(-row[score],row[name]))students[{name:小王,score:88},{name:小李,score:95},{name:小张,score:95}]rankedrank_students(students)assert[row[name]forrowinranked][小李,小张,小王]assertstudents[0][name]小王# 没有就地排序forrowinranked:print(f{row[name]}:{row[score]})同分时按姓名排序只是一个确定性示例产品也可以改成保留输入顺序。关键是通过key明确排序字段并让函数只负责排序不混入输入读取和打印。二、本篇要完成什么把购物清单改造成可复用的商品结算器。重点不是记住def而是理解函数如何接收输入、完成一个职责并返回结果。三、参数和返回值defcalculate_subtotal(items:list[dict])-float:计算商品小计不读取输入也不打印结果。returnsum(item[price]*item[quantity]foriteminitems)调用者提供items函数返回一个数字。return会结束当前函数如果没有 return默认返回None。把计算函数和交互函数分开测试时可以直接传列表不需要模拟键盘。四、默认参数和作用域defapply_discount(amount:float,rate:float1.0)-float:ifnot0rate1:raiseValueError(折扣必须大于0且不超过1)returnamount*ratedefcheckout(items:list[dict],discount_rate:float1.0)-float:subtotalcalculate_subtotal(items)returnround(apply_discount(subtotal,discount_rate),2)subtotal是函数内部变量函数结束后不会污染外部。不要依赖全局购物车否则不同用户同时结算时会互相影响这正是后端服务必须避免共享可变全局变量的原因。五、完整程序和运行结果defcalculate_subtotal(items:list[dict])-float:returnsum(item[price]*item[quantity]foriteminitems)defcheckout(items:list[dict],discount_rate:float1.0,delivery_fee:float0)-float:ifdelivery_fee0:raiseValueError(配送费不能为负)subtotalcalculate_subtotal(items)returnround(apply_discount(subtotal,discount_rate)delivery_fee,2)defapply_discount(amount:float,rate:float)-float:ifnot0rate1:raiseValueError(折扣必须在0和1之间)returnamount*rate cart[{name:键盘,price:99.9,quantity:1},{name:鼠标,price:39.9,quantity:2}]print(f原价{calculate_subtotal(cart):.2f})print(f结算价{checkout(cart,0.9,6):.2f})预期原价179.70九折加配送费后为167.73。课后练习为结算函数写三个断言下一篇将把账单保存为 JSON 文件。实战补充商品结算的函数设计函数设计先确定输入和输出再决定内部实现。商品结算可以拆成校验商品、计算小计、计算优惠和生成收据四个函数。fromdecimalimportDecimaldefline_total(item:dict)-Decimal:priceDecimal(str(item[price]))quantityint(item[quantity])ifprice0orquantity0:raiseValueError(商品价格和数量必须为正)returnprice*quantitydeforder_total(items:list[dict],shipping:Decimal)-Decimal:subtotalsum((line_total(item)foriteminitems),Decimal(0))discountDecimal(0.9)ifsubtotalDecimal(100)elseDecimal(1)return(subtotal*discountshipping).quantize(Decimal(0.01))生成器表达式适合求和但排错时可以先改成普通 for 循环打印每个商品小计。函数参数不依赖全局购物车测试可以直接传入列表。验收与课后练习验收空购物车、非法商品、满减和配送费课后增加优惠券函数并写出优惠叠加顺序下一篇保存 JSON 记账数据。本篇结束完整模块文件本节不是代码片段而是本篇结束时该模块的完整版本。请先备份旧文件再整体替换替换后重新运行本篇命令和测试。阅读时重点看本篇新增的函数、事务边界和错误处理未涉及的代码先不要自行删减。main.pydefcalculate(items,discount1.0):subtotalsum(price*quantityforprice,quantityinitems)returnround(subtotal*discount,2)cart[(19.9,2),(8.5,3)]print(calculate(cart),calculate(cart,0.9))