Files

88 lines
3.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第 3-4 课课堂练习Python 特殊方法与数据类
#
# 关键规则已经写入每部分题目,可以直接完成练习。
# 请保留题目、预期结果和自查说明。
# 第一部分:定义 OrderItem 数据类
# 1. 在类上方添加 @dataclass。
# 2. 定义三个字段,不需要手写 __init__
# product_name: str
# unit_price: float
# quantity: int = 1
#
# Java 对照提醒:
# - @dataclass 会生成 __init__、__repr__ 和 __eq__ 等常用方法;
# - 它类似减少 POJO 样板代码的工具,但不是 Java record 的完全等价物;
# - 数据类默认仍然可变,并不会自动进行运行时类型检查。
# 第二部分:使用 __post_init__ 校验字段
# 1. 定义 __post_init__(self) 方法。
# 2. unit_price 小于 0 时抛出 ValueError("单价不能小于 0。")。
# 3. quantity 小于或等于 0 时抛出 ValueError("数量必须大于 0。")。
#
# Java 对照提醒:
# - dataclass 自动生成 __init__ 后,会自动调用 __post_init__
# - 类型注解只表达预期类型,不会阻止负数,所以业务校验仍需手写。
# 第三部分:定义 subtotal 只读 property
# 1. 使用 @property 定义 subtotal(self),返回单价乘数量。
# 2. 调用方式应为 item.subtotal而不是 item.get_subtotal()。
# 第四部分:定义 __str__(self)
# 1. 返回“机械键盘 × 21000.0 元”格式的使用者友好文字。
# 2. 使用 self.subtotal 取得小计。
#
# 特殊方法提醒:
# - print(item) 和 str(item) 会调用 __str__
# - repr(item) 会使用 dataclass 自动生成的 __repr__
# - item_one == item_two 会使用自动生成的 __eq__ 比较全部字段。
# 第五部分:定义 ShoppingCart 数据类
# 1. 在类上方添加 @dataclass。
# 2. 定义 owner: str 字段。
# 3. 定义 items 字段:
# items: list[OrderItem] = field(default_factory=list)
# 4. 定义 add(self, item) 方法,把 item 添加到 self.items。
# 5. 定义 total 只读 property返回所有 item.subtotal 的总和。
#
# 重要提醒:
# - 不要写 items = [] 作为类级默认列表;
# - default_factory=list 会为每个 ShoppingCart 对象创建独立列表;
# - 这与 Java 实例字段通常在构造时 new ArrayList<>() 的目的相似。
# 第六部分:定义 main() 并验证行为
# 1. 创建两个内容相同的 OrderItem("机械键盘", 500.0, 2)。
# 2. 输出第一个对象,预期调用 __str__。
# 3. 输出 repr(item_one),观察自动生成的调试表示。
# 4. 输出“两个订单项相等True”。
# 5. 创建 ShoppingCart("小明") 和 ShoppingCart("小红")。
# 6. 只向小明的购物车添加第一个订单项。
# 7. 输出两个购物车的商品种类数,证明列表没有共享。
# 8. 输出小明购物车的总金额。
# 9. 使用 try...except 创建 OrderItem("错误商品", -1.0),捕获并输出错误。
# 10. 添加程序入口判断并调用 main()。
#
# 预期输出:
# 机械键盘 × 21000.0 元
# OrderItem(product_name='机械键盘', unit_price=500.0, quantity=2)
# 两个订单项相等True
# 小明的商品种类数1
# 小红的商品种类数0
# 小明购物车总金额1000.0 元
# 非法订单项已被阻止:单价不能小于 0。
# 完成后自查:
# 1. 是否没有为 OrderItem 手写 __init__、__repr__ 和 __eq__
# 2. 是否能区分 __str__ 的用户显示与 __repr__ 的调试表示;
# 3. 是否知道 dataclass 的相等比较默认比较字段值;
# 4. 是否使用 __post_init__ 完成运行时业务校验;
# 5. 是否使用 default_factory=list 避免共享可变默认值;
# 6. 是否只把运行错误、结果错误和关键知识点错误视为阻塞项。