如何正确实现观测站蟒蛇当观察者[应]销毁
问题描述:
我实现了一个Python观察者观察到的模式:如何正确实现观测站蟒蛇当观察者[应]销毁
这是可观察类:
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)
在观察者的析构函数。
你看过弱点吗?弱引用旨在解决这个问题,并且自2.4以来一直是Python的一个特性。 –