2016-11-22 8 views
5

내가 파이썬에서 관찰자 관찰 패턴을 구현 해요 :은 관찰자가있을 때 제대로 파이썬에서 관찰자를 구현하는 방법을 [해야] 파괴

이 관찰 클래스 :

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()를 호출하기 때문에 변수 할당의 참조되지 않은 이동합니다.

내가 Observer에 대한 추가 참조가 없으면 del을 호출하면 Observer.__del__이 호출됩니다. 이 시나리오

테스트 케이스는 다음과 같습니다

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

이 두 가지 결과가 있습니다 주석 처리되지

  • self.foo.addObserver(self) 경우 self.foo.addObserver(self)이 주석하는 경우, 그것은 foo changed from 23 to 44foo changed from 44 to 1
  • 을 출력을, 그것은 인쇄한다 Observer.__del__ called
+2

약한 부분을 보았습니까? 약한 참조는 정확하게이 문제를 해결하도록 설계되었으며 2.4 이후 Python의 기능이었습니다. –

답변

4

약한 참조가 문제를 해결할 것으로 보입니다. 옵저버를 변경하여 weak-references을 관리합니다 (예 : 에있는 list 대체). 또는 다른 약한 참조 컨테이너를 구현합니다. 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)를 호출 할 필요가 없습니다.