学习前提

理解函数作用域、列表与字典;本课开始对象状态与模块组织。

本课完成后你能做什么

用实例保存独立进度,理解模块入口和可复用接口。

先理解机制

类描述一组对象共享的行为,实例保存各自状态。__init__初始化实例,self代表当前对象。不要把每个课程的可变列表放成类属性,否则实例可能共享同一列表。简单记录可用字典,只有状态规则和行为值得一起维护时再考虑类。

封装不是把所有字段改成神秘名称,而是通过方法维护不变量,例如完成数不能大于总数。Python下划线更多是约定,不构成服务端安全权限。调用者仍应知道方法是否修改状态以及返回什么。

模块就是可导入的Python文件。顶层语句在首次导入时执行,所以演示与交互入口放在if __name__ == "__main__"下,导入时不会意外读取输入或打印报告。避免给文件起json.py这类遮蔽标准库的名字。

拆文件时先确定依赖方向:计算模块不应导入界面入口,入口调用计算模块。循环导入通常说明职责纠缠。初学项目不需要先搭建复杂包结构,两个职责明确的文件就能练习复用。

可运行示例

使用Python 3.11或更新版本,将代码保存为独立练习目录中的lesson.py,在该目录执行 python3 lesson.py;Windows也可使用 py lesson.py。示例只使用标准库。

class Progress:
    def __init__(self, total):
        if type(total) is not int or total < 0:
            raise ValueError("total must be a nonnegative integer")
        self.total = total
        self.done = 0

    def complete(self):
        self.done = min(self.total, self.done + 1)

    def percent(self):
        return 0 if self.total == 0 else self.done * 100 // self.total

if __name__ == "__main__":
    first = Progress(4)
    second = Progress(4)
    first.complete()
    print(first.percent(), second.percent())

推演与验证

预期25与0,证明实例独立。连续调用complete超过总数,百分比不超过100;total0得到0。把类放到progress_model.py并从另一个文件导入,导入过程应没有演示输出。

常见错误与边界

示例字段可直接修改,因此是不变量教学起点,不是完全强制约束的领域模型。不要把继承当成默认复用方式,组合一个Progress对象常比复杂继承树更简单。

动手练习

增加undo与reset方法,测试不小于0、重置后为0、其他实例不受影响。

参考解法与理由

undo用max约束,reset只修改当前self.done。测试在已经为0时撤销以及完成后重置,避免只测正常中间状态。

进一步阅读