我在python中实现了一个观察者可观察的模式:
这是Observable类:
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.__del__
位于某个Observer
对象的观察者列表中,那么Observable
永远不会被调用。
请注意,我不一定明确地销毁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
答案 0 :(得分:5)
弱参考似乎可以解决您的问题。
您可以将观察者更改为管理weak-references,例如,替换list
中的weakref.WeakKeyDictionary
,或者实施其他弱引用容器。顺便说一下,使用散列类型(如字典)也会比列表更好,因为删除观察者会更有效率。
答案 1 :(得分:1)
解决方案:(将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)
。