如何在对象变量批量变更时仅调用一次类函数?
批量更新对象变量时仅触发一次回调函数的解决方案
问题背景
需要实现:对象单个变量变更时触发回调函数,多个变量同时变更时,仅在所有变量更新完成后调用一次回调。
最初通过重写__setattr__实现,但初始化和批量赋值时,回调会被每个变量各调用一次,不符合需求:
class Test: def __init__(self, length: int = 0, data: list = []): self.data = data self.length = length def __setattr__(self, key, value): super().__setattr__(key, value) print(f"Variable {key} changed to {value}!") self.somecoolfunction() obj = Test(length=5, data=[1, 0, 0, 0, 1, 1]) obj.length, obj.data = 10, [1, 1, 1]
输出会触发四次打印(两次初始化、两次批量赋值),且somecoolfunction()被调用四次,而我们期望批量更新后仅调用一次。
尝试过新增update()方法,但IDE无法提示可修改变量,用户也可能直接赋值跳过该方法,实用性不足。
解决方案:上下文管理器+状态标记
通过给类添加一个批量更新状态标记,结合上下文管理器,实现单次/批量赋值的不同回调逻辑,同时保留IDE属性提示和直接赋值的便捷性。
实现代码
class Test: def __init__(self, length: int = 0, data: list = []): # 标记是否处于批量更新状态 self._updating = True # 初始化属性,此时不触发回调 self.data = data self.length = length # 初始化完成后关闭批量状态,触发一次回调 self._updating = False self.somecoolfunction() def __setattr__(self, key, value): # 跳过内部状态变量的处理,避免递归触发 if key == "_updating": super().__setattr__(key, value) return # 更新属性值 super().__setattr__(key, value) print(f"Variable {key} changed to {value}!") # 仅非批量更新状态下,触发回调 if not self._updating: self.somecoolfunction() def batch_update(self): # 定义上下文管理器,用于批量更新操作 class BatchUpdateContext: def __enter__(inner_self): # 进入批量更新状态 self._updating = True return self def __exit__(inner_self, exc_type, exc_val, exc_tb): # 退出批量更新状态,触发一次回调 self._updating = False self.somecoolfunction() return BatchUpdateContext() def somecoolfunction(self): print("=== Running somecoolfunction() once! ===") # 使用示例 if __name__ == "__main__": # 初始化时仅触发一次回调 obj = Test(length=5, data=[1, 0, 0, 0, 1, 1]) # 单个变量赋值,正常触发回调 print("\n--- 单个变量更新 ---") obj.length = 8 # 批量更新变量,仅在所有更新完成后触发一次回调 print("\n--- 批量变量更新 ---") with obj.batch_update(): obj.length = 10 obj.data = [1, 1, 1]
输出结果
Variable data changed to [1, 0, 0, 0, 1, 1]! Variable length changed to 5! === Running somecoolfunction() once! === --- 单个变量更新 --- Variable length changed to 8! === Running somecoolfunction() once! === --- 批量变量更新 --- Variable length changed to 10! Variable data changed to [1, 1, 1]! === Running somecoolfunction() once! ===
方案优势
- 保留直接赋值便捷性:单个变量赋值时,依然会自动触发回调,符合常规使用习惯
- 支持批量更新单次回调:通过
with obj.batch_update():块包裹批量赋值操作,所有变量更新完成后仅触发一次回调 - IDE友好:对象的
length、data属性能被IDE正常识别并提示,无需依赖特定方法 - 初始化可控:初始化阶段通过批量状态标记,避免多次触发回调,仅在初始化完成后调用一次
内容的提问来源于stack exchange,提问作者user23638776
相关产品推荐
相关产品推荐

