Python中不使用setter如何监测类内属性值的变更事件
实现方案
你需要的无需强制调用自定义setter的属性变更监听,可以通过Python内置的property装饰器实现,该方案下开发者仍然可以直接用potato.color = "xxx"的方式赋值,赋值操作会自动触发变更检测逻辑,不需要额外修改现有开发习惯。
核心实现逻辑:
- 用私有属性
_color存储color的实际值,避免递归触发赋值逻辑 - 通过
property装饰器定义color的getter和底层自动调用的setter,setter中自动对比新旧值,发生变更时触发异步事件 - event_publisher监听异步事件,触发后打印属性值
以下是可直接运行的完整代码:
import asyncio import random class Potato: def __init__(self): # 用私有属性存储实际值 self._color = "potato-yellow" # 异步事件标记color是否发生变更 self.color_change_event = asyncio.Event() @property def color(self): return self._color @color.setter def color(self, new_color): # 仅当值实际变化时触发事件 if new_color != self._color: self._color = new_color self.color_change_event.set() async def frequency_publisher(potato_): while True: print("Publish by time!", potato_.color) await asyncio.sleep(15) async def event_publisher(potato_): while True: # 等待color变更事件触发 await potato_.color_change_event.wait() print("Publish by event!", potato_.color) # 重置事件标记,等待下一次变更 potato_.color_change_event.clear() # 测试用协程:模拟开发者随机直接修改color属性,可删除 async def test_simulate_user_change(potato_): color_options = ["potato-yellow", "poison-green", "rotten-brown", "purple-potato"] while True: await asyncio.sleep(random.randint(2, 10)) new_color = random.choice(color_options) print(f"\n[模拟操作] 开发者直接赋值 potato.color = {new_color}") potato_.color = new_color if __name__ == '__main__': potato = Potato() try: asyncio.run(asyncio.gather( event_publisher(potato), frequency_publisher(potato), test_simulate_user_change(potato) )) except KeyboardInterrupt: pass
说明
该方案没有使用需要开发者主动调用的set_color类方法,所有对potato.color的直接赋值都会自动走内置的setter逻辑触发变更事件,不需要对现有业务代码做大量重构。
内容的提问来源于stack exchange,提问作者Dustin
相关产品推荐
相关产品推荐

