Python中注入类属性变更时触发属性setter的实现问题
解决方案:监听子类实例属性变更触发父类操作
你的核心误区在于:Spline3DViewer的spline3D setter仅在替换整个spline3D实例引用时触发,而修改实例内部的num属性属于直接操作对象的内部状态,并不会触发父类的属性setter——因为父类监控的是spline3D这个对象引用本身,不是引用指向对象的内部属性。
以下是几种可行的解决方案:
方案一:给Spline3D实现观察者模式(推荐)
让Spline3D维护观察者列表,当属性变更时主动通知所有注册的观察者(如Spline3DViewer),触发对应操作。这种方式解耦了两个类,支持多观察者场景。
class Spline3D: def __init__(self, num=20): self._num = num self._observers = [] # 存储所有观察者 def add_observer(self, observer): self._observers.append(observer) def remove_observer(self, observer): self._observers.remove(observer) def _notify_observers(self): # 属性变更时通知所有观察者 for observer in self._observers: observer.on_spline_updated(self) @property def num(self): return self._num @num.setter def num(self, value): self._num = value self._notify_observers() # 触发通知 class Spline3DViewer: def __init__(self, spline3D): self._spline3D = spline3D spline3D.add_observer(self) # 注册为观察者 def on_spline_updated(self, spline): # 属性变更时执行的自定义操作 print(f"Updated self.spline3D.num is = {spline.num}") # 测试 spline3D = Spline3D(num=30) spline3DViewer = Spline3DViewer(spline3D=spline3D) spline3D.num = 40 # 输出:Updated self.spline3D.num is = 40
方案二:在Viewer中代理子类属性(无需修改Spline3D)
如果无法修改Spline3D的实现,可以在Spline3DViewer中提供代理属性,让外部通过Viewer来修改子类的属性,从而触发Viewer的逻辑。
class Spline3D: def __init__(self, num=20): self.num = num class Spline3DViewer: def __init__(self, spline3D): self._spline3D = spline3D @property def spline_num(self): return self._spline3D.num @spline_num.setter def spline_num(self, value): self._spline3D.num = value print(f"Updated self.spline3D.num is = {self._spline3D.num}") # 测试 spline3D = Spline3D(num=30) spline3DViewer = Spline3DViewer(spline3D=spline3D) spline3DViewer.spline_num = 40 # 输出:Updated self.spline3D.num is = 40
方案三:重写Spline3D的__setattr__钩子(侵入性强)
通过重写__setattr__方法监控所有属性的赋值操作,但这种方式会监控所有属性的变更(包括初始化时的赋值),需要额外处理避免误触发,仅在需要监控所有属性时使用。
class Spline3D: def __init__(self, num=20): self._observers = [] # 初始化属性时直接调用父类__setattr__,跳过通知逻辑 super().__setattr__('num', num) def add_observer(self, observer): self._observers.append(observer) def _notify_observers(self): for observer in self._observers: observer.on_spline_updated(self) def __setattr__(self, name, value): super().__setattr__(name, value) # 排除观察者列表本身的变更通知 if name != '_observers': self._notify_observers() class Spline3DViewer: def __init__(self, spline3D): self._spline3D = spline3D spline3D.add_observer(self) def on_spline_updated(self, spline): print(f"Updated attribute: num = {spline.num}") # 测试 spline3D = Spline3D(num=30) spline3DViewer = Spline3DViewer(spline3D=spline3D) spline3D.num = 40 # 输出:Updated attribute: num = 40
内容的提问来源于stack exchange,提问作者TheNomad
相关产品推荐
相关产品推荐

