如何以非取巧方式在Python类实例间共享布尔状态?
更合理的Cat类共享状态实现方式
原代码与需求
假设我有如下代码:
class Cat: def __init__(self, var, n_calls=None): self.var = var if n_calls is None: self.n_calls = [] else: self.n_calls = n_calls def greet(self): if self.n_calls: raise ValueError('Already greeted, sorry') self.n_calls.append(1) print('hello') def change_var(self, new_var): return Cat(new_var, n_calls=self.n_calls)
需求是:
- 单个
Cat实例所属的分支只能执行一次greet方法 - 从同一初始
Cat派生的所有实例共享同一调用状态,只要有一个实例执行过greet,同分支的其他实例都无法再执行该方法
示例验证
cat = Cat(3) new_cat = cat.change_var(4) other_cat = cat.change_var(5) cat2 = Cat(6) new_cat.greet() # 执行成功 cat2.greet() # 执行成功 other_cat.greet() # 抛出异常
解释:
new_cat.greet()执行成功,因为这是该分支首次调用greetcat2.greet()执行成功,因为它属于独立的初始Cat分支other_cat.greet()抛出异常,因为它和new_cat共享同一分支状态,而new_cat已经调用过greet
问题:原实现的“取巧”之处
原代码利用了列表的可变性来共享状态——用空列表表示未调用过greet,非空列表表示已调用。但列表的语义是有序元素集合,用来充当布尔标志的容器不符合代码的直观意图,可读性差,后续维护时容易让人困惑。
更合理的实现方式
方案1:自定义共享状态类
用一个专门的类封装共享状态,语义明确,可读性强:
class GreetState: def __init__(self): self.has_greeted = False class Cat: def __init__(self, var, state=None): self.var = var # 新实例若未传入状态,则创建新的状态对象;否则复用传入的状态 self.greet_state = state or GreetState() def greet(self): if self.greet_state.has_greeted: raise ValueError('Already greeted, sorry') self.greet_state.has_greeted = True print('hello') def change_var(self, new_var): # 派生新实例时,复用当前实例的状态对象 return Cat(new_var, state=self.greet_state)
方案2:使用简单可变对象(可选)
如果不想额外定义类,也可以用单个元素的dict来封装状态(但语义不如自定义类清晰):
class Cat: def __init__(self, var, state=None): self.var = var self.greet_state = state or {'has_greeted': False} def greet(self): if self.greet_state['has_greeted']: raise ValueError('Already greeted, sorry') self.greet_state['has_greeted'] = True print('hello') def change_var(self, new_var): return Cat(new_var, state=self.greet_state)
这两种方式都通过显式共享可变状态对象实现需求,代码意图清晰,避免了利用列表语义不符的“取巧”写法。
内容的提问来源于stack exchange,提问作者ignoring_gravity
相关产品推荐
相关产品推荐

