学习前提
理解函数作用域、列表与字典;本课开始对象状态与模块组织。
本课完成后你能做什么
用实例保存独立进度,理解模块入口和可复用接口。
先理解机制
类描述一组对象共享的行为,实例保存各自状态。__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时撤销以及完成后重置,避免只测正常中间状态。