CS1602计算导论
Lab 10Part 4 抽象与组织AI Level 1

继承、运算符重载与模块 · 个人项目 B 启动

五道题练继承、特殊方法和模块组织,然后是个人项目 B——大整数运算,一个必须自己实现底层的题目。

截止:小作业 4 · 12 月 8 日 周二 23:59
本页目录

本次目标

  • 用继承和多态组织一组相关的类
  • 通过特殊方法让自己的类融入 Python 的语法
  • 把代码拆成模块,用 if __name__ == "__main__": 守住入口
  • 启动个人项目 B

题目

10-1 图形家族

写一个 Shape 基类和三个子类:

class Shape:
    def area(self) -> float: ...          # 基类抛 NotImplementedError
    def name(self) -> str: ...            # 返回类名

class Circle(Shape):    def __init__(self, r: float) -> None: ...
class Rectangle(Shape): def __init__(self, w: float, h: float) -> None: ...
class Triangle(Shape):  def __init__(self, a: float, b: float, c: float) -> None: ...

三角形用海伦公式算面积。再写一个模块级函数:

def total_area(shapes: list[Shape]) -> float: ...

10-2 账户继承

在 L9 的 BankAccount 基础上,写两个子类:

  • SavingsAccount:多一个 interest_rate,有 add_interest() 方法
  • CheckingAccount:允许透支到 -overdraft_limit

两个子类的 __init__ 都要用 super().__init__(...)。CheckingAccount 要重写 withdraw。

在提交说明里回答:CheckingAccount.withdraw 里你调用 super().withdraw() 了吗?为什么?

10-3 Money 类

实现一个 Money 类,内部用整数分存储(L2 讲过为什么不能用浮点数存钱):

class Money:
    def __init__(self, yuan: float) -> None: ...   # 转成分存
    def __repr__(self) -> str: ...                 # 如 Money(12.50)
    def __add__(self, other: "Money") -> "Money": ...
    def __sub__(self, other: "Money") -> "Money": ...
    def __eq__(self, other: object) -> bool: ...
    def __lt__(self, other: "Money") -> bool: ...

要求这些都能正常工作:

Money(10.50) + Money(0.25)          # Money(10.75)
sorted([Money(3), Money(1), Money(2)])
Money(0.1) + Money(0.2) == Money(0.3)   # 必须是 True

10-4 可迭代的容器

实现一个 Deck 类表示一副扑克牌(52 张,不含大小王):

class Deck:
    def __init__(self) -> None: ...
    def __len__(self) -> int: ...
    def __getitem__(self, i: int) -> str: ...
    def __contains__(self, card: str) -> bool: ...
    def shuffle(self) -> None: ...
    def deal(self, n: int) -> list[str]: ...    # 发 n 张,从牌堆移除

牌面表示自定(比如 "红桃A" 或 "AH"),在提交说明里说明你的表示法。

实现了 __getitem__ 之后,下面这些都应该能用:

len(deck)
deck[0]
"红桃A" in deck
for card in deck: ...

10-5 拆成模块

把 10-1 到 10-4 的代码整理成三个文件:

shapes.py      # 10-1
accounts.py    # 10-2
cards.py       # 10-3、10-4
main.py        # 演示,import 上面三个

每个模块都要有:

  • 文件顶部的模块文档字符串
  • if __name__ == "__main__": 块,里面放该模块的自测代码

然后验证:运行 python3 main.py 时,三个模块的自测代码不应该被执行。 把验证过程写在提交说明里。


个人项目 B:任意精度整数运算

占总成绩 7.5% 截止:两周后的周日 23:59

背景

L2 说过 Python 的整数没有上限——2 ** 2000 能直接算出来。但大多数语言做不到,它们的整数有固定位数。

Python 是怎么做到的?答案是:用一个数组存下每一位,自己实现加减乘。这个项目就是让你造一遍这个轮子。

要求

实现一个 BigInt 类,内部不能使用 Python 的大整数运算——也就是说,你不能把两个数转成 int 相加再转回来。

class BigInt:
    def __init__(self, value: str) -> None:
        """从十进制字符串构造,如 BigInt("123456789012345678901234567890")。
        要支持前导负号。"""

    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def __lt__(self, other: "BigInt") -> bool: ...
    def __add__(self, other: "BigInt") -> "BigInt": ...
    def __sub__(self, other: "BigInt") -> "BigInt": ...
    def __mul__(self, other: "BigInt") -> "BigInt": ...

分项

部分分值说明
加法20%含进位、含不等长
减法20%含借位、结果为负
乘法20%竖式乘法即可,不要求高级算法
比较(__eq__、__lt__)10%要能正确排序,含负数
边界与健壮性15%见下
代码质量5%类型提示、拆分、命名
报告10%见下

必须处理的边界

  • BigInt("0"),以及结果为 0 的运算
  • 前导零:BigInt("00123") 应等于 BigInt("123")
  • 负数:加减乘的符号规则
  • 不等长的两个数相加相减
  • 减法结果为负:BigInt("5") - BigInt("8")

报告要求

不超过一页,回答三个问题:

  1. 你的内部表示是什么? 每一位存一个数字,还是每格存多位?为什么这么选?
  2. 符号是怎么处理的? 你把符号单独存了,还是让每一位带符号?加减法的符号规则你是怎么理清的?
  3. 你怎么测试的? 具体说明你用了哪些边界用例,以及有没有用随机对拍。

提交前自查

  • 10-1 到 10-4 所有类和方法都有类型提示
  • 10-3 的 Money(0.1) + Money(0.2) == Money(0.3) 为 True
  • 10-4 的 for card in deck 能用
  • 10-5 验证了自测代码没有被 import 触发
  • 项目 B:五类边界都测过
  • 项目 B:报告三个问题都回答了
  • AI 使用声明写了