How to properly implement Observer in python when an observer [should] be destroyed

I implement an observable observable pattern in python:

This is the Observable class:

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) 

and this is the observer:

 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)) 

The code works as expected.

But I need the Observer be destroyed (i.e. when it is not displayed, it must be removed from the list of observers in the Observable object).

The problem is that with this code, Observer.__del__ never called if Observer is on the observer list of some Observable .

Note that I do not necessarily destroy Observer explicitly, it will also be impossible due to the assignment of a variable, thereby calling removeObserver() explicitly before destruction is not viable .

If I comment on self.foo.addObserver(self) , then there are no additional references to Observer , and calling del on it will call Observer.__del__ .

Test file for this scenario:

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

It has two results:

  • If self.foo.addObserver(self) not commented out, it prints foo changed from 23 to 44 and foo changed from 44 to 1
  • If self.foo.addObserver(self) commented out, it prints Observer.__del__ called
+6
source share
2 answers

Solution: (changed Observable.observers to 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) 

In addition, you do not need to call .removeObserver(self) in the observer destructor.

+1
source

Source: https://habr.com/ru/post/1012560/


All Articles