如何正确实现观测站蟒蛇当观察者[应]销毁

如何正确实现观测站蟒蛇当观察者[应]销毁

问题描述:

我实现了一个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 44foo changed from 44 to 1
  • 如果self.foo.addObserver(self)被注释掉,它打印Observer.__del__ called
+2

你看过弱点吗?弱引用旨在解决这个问题,并且自2.4以来一直是Python的一个特性。 –

看来,弱引用将解决您的问题。 您可以更改观察者以管理weak-references,例如,通过替换weakref.WeakKeyDictionary中的list,或者通过实施其他弱引用容器。顺便说一句,使用哈希类型,如字典,也会比列表更好,因为移除观察者将更加高效。

解决方案:(改Observable.observersweakref.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)在观察者的析构函数。