Python基础语法练习题(73)

题目:定义一个简单的在线购物车类,支持添加商品、删除商品、查看购物车内容以及计算总价的功能。

看到这道题的第一反应:购物车?这不就是我天天在用的东西吗?可要自己用代码写出来,还真得想清楚"一个商品该用什么存、一类东西该怎么管"。

一、我的思路:先想清楚"用什么存"

购物车本质上就是一堆"商品名 → 数量和单价"的对应关系,所以我一眼就想到了字典。

但这里有个细节:光用一层字典不够,因为一个商品同时有"数量"和"单价"两个信息。所以我最终选的是嵌套字典 :外层字典的键是商品名,值是一个小字典,里面放着 quantity 和 price。

self.cart: dictstr, dict\[str, float] = {}

一开始我还有点疑惑:后面那串 : dict[str, dict[str, float]] 是什么?后面才知道,这是类型注解 。

我一开始不写它,PyCharm 会把从字典里取出来的商品信息推断成 Any(也就是"啥都可能"),后面一旦拿去做运算,就会衍生一堆类型警告。显式标注之后,编辑器就知道取出来的值一定是浮点数,世界瞬间清净了。

二、四个方法,各管一件事

类里我写了四个实例方法,正好对应题目的四个功能:

  • add_product() 添加商品:这里我处理了一个容易忽略的场景------同名商品重复添加怎么办。我的做法是:如果商品已在购物车里,就把数量累加,单价更新为本次输入的价;如果是新商品,就正常创建一条记录。

  • remove_product() 删除商品 :先用 in 判断商品存不存在,存在就用 del 删掉并返回 True;不存在就提示后返回 False,不硬删,避免报错。

  • view_cart() 查看购物车 :遍历 self.cart.items(),把每个商品的数量、单价、小计一行行打印出来。注意:如果购物车是空的,要单独给一句提示,直接 return 提前结束方法。

  • calculate_total_price() 计算总价 :把每个商品的"数量 × 单价"累加起来。这里我把初始值定为 0.0 而不是 0,这样不管购物车空不空,返回类型都稳定是浮点数。

三、我踩过的坑:差点把购物车写成"input 机器人"

写第一版的时候,我很自然地把 input() 塞进了类的添加、删除方法里,让方法自己问用户要数据。

结果就是:PyCharm 报了我一脸警告(整整 8 个),而且整个类被"提问 - 等待 - 校验"挤得面目全非。

后来我意识到一个原则:类只负责逻辑,菜单只负责交互。

于是我把结构调整成三层:

  1. ShoppingCart 类:只接收已经校验好的干净数据,专心做增删查算;

  2. 输入辅助函数 :input_name()、input_quantity()、input_price() 三个函数,专门负责问用户要数据并校验;

  3. 主程序菜单 :一个 while True 循环打印 12340 选项,用户选什么就调用对应的函数和方法。

这样每一块都只有一个小职责,改任何一块都不影响其他块。

四、输入校验的固定套路:标志位循环

你可能会问:用户输了小数、字母、负数怎么办?我用了一个在之前 101 题里也出现过的套路,就是**"标志位循环 + 循环外统一返回"**:

quantity = 1

valid = False

while not valid:

try:

value = int(input(prompt))

except ValueError:

print(' 输入无效 数量必须是整数。')

continue

if value <= 0:

print(' 输入无效 数量必须是大于 0 的正整数。')

continue

quantity = value

valid = True

return quantity

这里有三个要点:

  1. 用 try/except 接住非数字输入,程序不崩溃,而是重新提示。

  2. 范围校验放在 try 外面用独立 if 判断,职责更清楚。

  3. return 写在循环外面,检查器就能认定返回值类型恒定,不会出现"可能返回 None"的告警。

五、顺带修正的两个小细节

  1. 类名复数问题 :第一版我写的是 ShoppingCarts(复数),但一个购物车对象明明是单数,于是修正为 ShoppingCart。这种只在文件内部使用的类,改名是安全的。

  2. "又打印又返回"的毛病 :原版 calculate_total_price() 是自己在方法里打印总价、同时又 return 的。我把打印拿掉了,方法只负责返回总价,打印交给主程序去做格式化。好处是:这个方法以后想复用到别的地方(比如写到文件、传给别的函数),都不会带着多余的打印行为。

六、小结

这道题练到的东西比表面看起来多:

  • 嵌套字典做"一对多属性"的存储结构;

  • __init__ 里初始化实例属性;

  • 方法只写逻辑、交互交给主程序菜单的职责分离思想;

  • 标志位循环的输入校验套路;

  • 以及类型注解消除警告的小技巧。

写完最大的感受是:代码能跑只是及格线,把"谁该干什么"想清楚,才算真正入门了面向对象。

相关推荐
Wang's Blog1 小时前
Java 项目实战: 交友项目 - 环信后台发送消息测试
java·交友
锋行天下1 小时前
Langgraph HITL 中断运行,用户输入后输出打字效果
人工智能·python
用户3721574261351 小时前
Java 操作 Word 脚注和尾注:添加、读取与删除
java
风骏时光牛马2 小时前
面向复杂场景的大模型应用落地与能力优化实践
前端
时早玖沐2 小时前
给 AstrBot 写一个天气推送插件:12 次提交、6 个坑
python·开源·ai编程
小小善后师2 小时前
我做了个病历归档小程序,被 AI 识别的"最后一公里"狠狠上了一课
前端
触底反弹2 小时前
🚀 FastAPI 五大重难点深度剖析:从 500 报错到彻底搞懂 Depends、Pydantic 与 SQLAlchemy
python·fastapi
cpolar技术支持2 小时前
网关加 gzip,同时开启 chunked,下载回来的包解不开:把两层编码的解压顺序与长度核对做成只读页
python·http·网络编程·socket·内网穿透
小嘉丶学长2 小时前
Day14 · 字典与集合
java·开发语言·网络·python·学习·1024程序员节