2016-11-22 69 views
5

我實現了一個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的一個特性。 –

回答

4

看來,弱引用將解決您的問題。 您可以更改觀察者以管理weak-references,例如,通過替換weakref.WeakKeyDictionary中的list,或者通過實施其他弱引用容器。順便說一句,使用哈希類型,如字典,也會比列表更好,因爲移除觀察者將更加高效。

0

解決方案:(改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)在觀察者的析構函數。