ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

零基础入门python06:把重复代码变成函数——商品结算器

零基础入门python06:把重复代码变成函数——商品结算器

零基础入门python06:把重复代码变成函数——商品结算器

一、上一篇课后练习讲解

成绩统计练习要求输出排名。参考做法是sorted(scores, reverse=True)生成新列表,不直接修改原始成绩;如果要同时保留姓名和成绩,应排序字典列表的score字段。

可执行验收答案

defrank_students(rows:list[dict])->list[dict]:"""返回新列表,原始列表顺序和内容保持不变。"""returnsorted(rows,key=lambdarow:(-row["score"],row["name"]))students=[{"name":"小王","score":88},{"name":"小李","score":95},{"name":"小张","score":95}]ranked=rank_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:float=1.0)->float:ifnot0<rate<=1:raiseValueError('折扣必须大于0且不超过1')returnamount*ratedefcheckout(items:list[dict],discount_rate:float=1.0)->float:subtotal=calculate_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:float=1.0,delivery_fee:float=0)->float:ifdelivery_fee<0:raiseValueError('配送费不能为负')subtotal=calculate_subtotal(items)returnround(apply_discount(subtotal,discount_rate)+delivery_fee,2)defapply_discount(amount:float,rate:float)->float:ifnot0<rate<=1: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:price=Decimal(str(item['price']))quantity=int(item['quantity'])ifprice<=0orquantity<=0:raiseValueError('商品价格和数量必须为正')returnprice*quantitydeforder_total(items:list[dict],shipping:Decimal)->Decimal:subtotal=sum((line_total(item)foriteminitems),Decimal('0'))discount=Decimal('0.9')ifsubtotal>=Decimal('100')elseDecimal('1')return(subtotal*discount+shipping).quantize(Decimal('0.01'))

生成器表达式适合求和,但排错时可以先改成普通 for 循环打印每个商品小计。函数参数不依赖全局购物车,测试可以直接传入列表。

验收与课后练习

验收空购物车、非法商品、满减和配送费;课后增加优惠券函数并写出优惠叠加顺序,下一篇保存 JSON 记账数据。

本篇结束:完整模块文件

本节不是代码片段,而是本篇结束时该模块的完整版本。请先备份旧文件,再整体替换;替换后重新运行本篇命令和测试。阅读时重点看本篇新增的函数、事务边界和错误处理,未涉及的代码先不要自行删减。

main.py

defcalculate(items,discount=1.0):subtotal=sum(price*quantityforprice,quantityinitems)returnround(subtotal*discount,2)cart=[(19.9,2),(8.5,3)]print(calculate(cart),calculate(cart,0.9))
返回列表