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

类的设计与实现

六道题。前四题写类,第五题是把已有的字典代码重构成类,最后一题要求你判断"该不该用类"——有时候答案是不该。

截止:小作业 3 · 11 月 17 日 周二 23:59
本页目录

本次目标

  • 熟练写出带 __init__ 和方法的类
  • 分清实例变量和类变量
  • 体会封装如何守住数据的合法性
  • 建立”什么时候不该用类”的判断

题目

9-1 矩形

实现 Rectangle 类:

class Rectangle:
    def __init__(self, width: float, height: float) -> None: ...
    def area(self) -> float: ...
    def perimeter(self) -> float: ...
    def is_square(self) -> bool: ...
    def scale(self, factor: float) -> None: ...     # 原地缩放
r = Rectangle(3, 4)
r.area()       →  12
r.perimeter()  →  14
r.is_square()  →  False
r.scale(2); r.area()  →  48

在提交说明里回答:scale 你让它原地改还是返回新对象?为什么?

9-2 栈

实现 Stack 类,先进后出(L7 讲调用栈时提过):

class Stack:
    def __init__(self) -> None: ...
    def push(self, item: int) -> None: ...
    def pop(self) -> int: ...
    def peek(self) -> int: ...
    def is_empty(self) -> bool: ...
    def size(self) -> int: ...

空栈上 pop 该怎么办? 你有三个选择:返回 None、抛异常、或者先要求调用方检查。三种都合理,但你要选一个并说明理由,写在提交说明里。

9-3 计数器

实现 WordCounter 类:

class WordCounter:
    def __init__(self) -> None: ...
    def add(self, word: str) -> None: ...            # 计数加一
    def get(self, word: str) -> int: ...             # 查询,没见过返回 0
    def total(self) -> int: ...                      # 所有计数之和
    def most_common(self, n: int) -> list[tuple[str, int]]: ...

most_common 的排序规则和 Lab 6 一样:次数从多到少,相同则按字母序。

9-4 温度:让封装守住规则

实现 Temperature 类,内部用摄氏度存储:

class Temperature:
    def __init__(self, celsius: float) -> None: ...
    def celsius(self) -> float: ...
    def fahrenheit(self) -> float: ...
    def kelvin(self) -> float: ...
    def set_celsius(self, value: float) -> bool: ...   # 成功返回 True

要求:低于绝对零度(−273.15°C)的设置必须被拒绝,返回 False 且不改变原值。

内部存储用 self._celsius(单下划线)。

在提交说明里回答:如果不用类,而是让每个人自己拿一个 celsius 变量算来算去,会出什么问题?

9-5 重构:从字典到类

下面是一段能用的代码。把它重构成一个 Gradebook 类。

def add_score(book, name, subject, score):
    if name not in book:
        book[name] = {}
    book[name][subject] = score

def average(book, name):
    scores = book[name].values()
    return sum(scores) / len(scores)

def top_student(book):
    return max(book, key=lambda n: average(book, n))

gb = {}
add_score(gb, "张三", "数学", 87)
add_score(gb, "张三", "物理", 92)
add_score(gb, "李四", "数学", 65)
print(average(gb, "张三"), top_student(gb))

新的类应提供 add(name, subject, score)、average(name)、top_student()。

同时修掉原代码里的两个问题(提示:查一个不存在的学生会怎样?没有学生的时候 top_student 会怎样?)。在提交说明里说明你修了什么。

9-6 该不该用类

下面四个需求,判断该用类还是不该,各写一句话理由:

  1. 把摄氏度转成华氏度
  2. 表示一副扑克牌,能洗牌、发牌、查看剩余张数
  3. 判断一个字符串是不是回文
  4. 一个聊天机器人,要记住对话历史并据此回复

提交前自查

  • 所有类和方法都有类型提示
  • 9-2 的空栈处理方式选了一种并说明了理由
  • 9-3 造了两个对象,确认数据没有串
  • 9-4 用 -300 测过,确认被拒绝
  • 9-5 修了原代码的两个问题并说明了
  • 9-6 四条都有理由,且不全是”该用类”
  • AI 使用声明写了