Python 类与对象:封装任务状态并避免实例共享数据
把任务标题、完成状态与完成操作组织到一个类中,比较两个任务实例的独立状态,并说明类属性与实例属性的使用边界。
本节目标
把任务标题、完成状态与完成操作组织到一个类中,比较两个任务实例的独立状态,并说明类属性与实例属性的使用边界。
知识与使用场景
当多个操作围绕同一份状态展开时,类能把数据与行为放在一起。任务拥有标题和完成状态,完成操作负责把状态从未完成改为完成。调用者无需到处记住字典键名,而是调用任务提供的方法。
__init__ 在新实例初始化时执行,self 指向当前实例。把 done 赋给 self,两个任务就分别保存自己的完成状态。若把可变的列表写在类体中,它通常会被实例共同访问,这与“每个任务有自己的标签”并不相同。
本节对标题做最小校验:必须是字符串,去掉首尾空白后不能为空。完成方法多次调用都把 done 设为 True,具有幂等行为。它没有模拟数据库保存或权限检查,实例变化只存在于本次进程内。
完整示例
class Task:
def __init__(self, title):
if not isinstance(title, str):
raise TypeError("标题必须是字符串")
title = title.strip()
if not title:
raise ValueError("标题不能为空")
self.title = title
self.done = False
def complete(self):
self.done = True
def describe(self):
state = "已完成" if self.done else "待完成"
return f"{self.title}:{state}"
first = Task("练习类")
second = Task("补充测试")
first.complete()
first.complete()
print(first.describe())
print(second.describe())预期结果
练习类:已完成
补充测试:待完成运行与逐步理解
构造 first 和 second 后,它们拥有不同的实例状态。对 first 连续调用两次 complete,并不会把 second 改成已完成,也不会把 first 切回待完成,因为方法采用赋值而不是反转布尔值。
describe 返回文本,调用者再选择打印、写文件或传给界面。让对象方法返回结果比直接打印更容易测试。若以后需要显示完成时间,可以新增实例属性,并明确第二次完成是否更新它,不能只凭方法名猜测。
Python 的普通属性仍可被外部直接修改。本例的校验只发生在构造时,first.title = '' 不会自动再次调用校验。若业务要求始终保持约束,需要增加受控修改方法或 property,并让调用代码遵守约定。
常见问题与边界
- 方法定义遗漏 self,会在实例调用时出现参数数量错误。
- 类体里的
tags = []容易让多个实例共享标签,应在初始化中创建self.tags = []。 done = True只创建局部变量;修改实例状态需要写self.done = True。- 不必为了使用类而把所有小函数都包装成类,只有相关状态和行为才值得组合。
动手练习
给 Task 增加 reopen 方法,让已完成任务重新待办;再验证空白标题会被拒绝。
参考答案
在类中添加 def reopen(self):,函数体写 self.done = False。调用 first.reopen() 后 describe 应返回“练习类:待完成”;Task(" ") 应抛 ValueError,而不是创建看起来没有标题的任务。
文章回复
0 条公开回复