2016-11-22 3 views
5

を破壊しましたオブザーバー:は、[する必要があります]私はPythonでオブザーバー-observableパターンを実装しています

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オブジェクト内のオブザーバーのリストから自身を削除する必要があります)。

ObserverObservableオブジェクトのオブザーバーのリストにある場合、このコードではObserver.__del__が呼び出されないという問題があります。私は必ずしも明示的Observerを破壊しない

注意、それはまた、これ実行可能でない破壊に明示的に前removeObserver()を呼び出し、理由変数の代入を参照されない移動します。

私がself.foo.addObserver(self)をコメントアウトした場合、Observerへの追加の参照はなく、delを呼び出すとObserver.__del__が呼び出されます。

このシナリオのテストケースがある:self.foo.addObserver(self)がコメントアウトされていない場合self.foo.addObserver(self)がコメントアウトされている場合、それは、foo changed from 23 to 44foo changed from 44 to 1

  • を印刷し

    • foo = Observable(23) 
      bar = Observer(foo) 
      foo.set(44) 
      bar = None 
      foo.set(1) 
      

      それは2つの結果を持っていますそれは印刷するObserver.__del__ called

  • +2

    弱点を見ましたか?弱い参照はこの問題を正確に解決するように設計されており、2.4以降のPythonの機能となっています。 –

    答えて

    4

    弱い参照が問題を解決するようです。 weak-referencesを管理するようにオブザーバを変更します。たとえば、をweakref.WeakKeyDictionaryに置き換えるか、他の弱参照コンテナを実装します。また、オブザーバを削除する方がはるかに効率的になるので、辞書などのハッシュ型を使用するBTWもリストより優れています。

    0

    ソリューション:(weakref.WeakKeyDictionaryObservable.observersを変更)

    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)を呼び出すために必要とされていません。

    関連する問題