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")
报告要求
不超过一页,回答三个问题:
- 你的内部表示是什么? 每一位存一个数字,还是每格存多位?为什么这么选?
- 符号是怎么处理的? 你把符号单独存了,还是让每一位带符号?加减法的符号规则你是怎么理清的?
- 你怎么测试的? 具体说明你用了哪些边界用例,以及有没有用随机对拍。
提交前自查
- 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 使用声明写了