当观察者 [应该] 被销毁时,如何在 python 中正确实施观察者
how to properly implement Observer in python when the observer is [should be] destroyed
我正在 python:
中实现观察者可观察模式这是 Observable class:
class Observable(object):
def __init__(self, value):
self.value = value
self.observers = []
def set(self, value):
old = self.value
self.value = value
self.notifyObservers(old, self.value)
def get(self):
return self.value
def addObserver(self, o):
self.observers.append(o)
def removeObserver(self, o):
if o in self.observers:
self.observers.remove(o)
def notifyObservers(self, old, new):
for o in self.observers:
o.valueChanged(old, new)
这是一个观察者:
class Observer(object):
def __init__(self, foo):
self.foo = foo
self.foo.addObserver(self)
def __del__(self):
print('Observer.__del__ called')
self.foo.removeObserver(self)
def valueChanged(self, old, new):
print('foo changed from %s to %s' % (old, new))
代码按预期工作。
但我需要销毁 Observer
(即,当它未被引用时,它应该将自己从 Observable
对象的观察者列表中删除)。
问题在于,使用此代码,如果 Observer
在某些 Observable
对象的观察者列表中,则 Observer.__del__
永远不会被调用。
请注意,我不一定要显式销毁 Observer
,由于变量赋值,它也将不再被引用,因此在销毁 之前显式调用 removeObserver()
是不可行的.
如果我注释掉self.foo.addObserver(self)
,那么就没有对Observer
的额外引用,调用del
就会调用Observer.__del__
.
这个场景的测试用例是:
foo = Observable(23)
bar = Observer(foo)
foo.set(44)
bar = None
foo.set(1)
它有两个结果:
- 如果
self.foo.addObserver(self)
没有被注释掉,它会打印foo changed from 23 to 44
和foo changed from 44 to 1
- 如果
self.foo.addObserver(self)
被注释掉,它会打印Observer.__del__ called
看来弱引用可以解决你的问题。
您更改观察者以管理 weak-references,例如,通过替换 weakref.WeakKeyDictionary
中的 list
,或通过实现其他一些弱引用容器。顺便说一句,使用散列类型(例如字典)也比列表更好,因为删除观察者会更有效率。
解决方案:(将Observable.observers
更改为weakref.WeakKeyDictionary
)
class Observable(object):
def __init__(self, value):
self.value = value
self.observers = weakref.WeakKeyDictionary()
def set(self, value):
old = self.value
self.value = value
self.notifyObservers(old, self.value)
def get(self):
return self.value
def addObserver(self, o):
self.observers[o] = 1
def removeObserver(self, o):
del self.observers[o]
def notifyObservers(self, old, new):
for o in self.observers:
o.valueChanged(old, new)
此外,不需要在观察者的析构函数中调用.removeObserver(self)
。