I'm implementing an observer-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 an 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
to be destroyed (i.e. when it goes unreferenced, it should remove itself from the list of observers in the Observable
object).
The problem is that with this code, Observer.__del__
never gets called if the Observer
is in the list of observers of some Observable
object.
Note that I don't necessarily destroy the Observer
explicitly, it will also go unreferenced because of variable assignment, thus calling removeObserver()
explicitly prior to destruction is not viable.
If I comment out self.foo.addObserver(self)
, then there are no additional references to Observer
, and calling del
on it will call Observer.__del__
.
The testcase for this scenario is:
foo = Observable(23)
bar = Observer(foo)
foo.set(44)
bar = None
foo.set(1)
it has two outcomes:
self.foo.addObserver(self)
is not commented out, it prints foo changed from 23 to 44
and foo changed from 44 to 1
self.foo.addObserver(self)
is commented out, it prints Observer.__del__ called
The Observer pattern addresses the following problems: A one-to-many dependency between objects should be defined without making the objects tightly coupled. It should be ensured that when one object changes state, an open-ended number of dependent objects are updated automatically.
The Observer design pattern is modeled on the event-driven programming paradigm . Just like other design patterns, this pattern lets us define loosely coupled systems. Leveraging this pattern, we can write maintainable and modular software.
Observer is a behavioral design pattern that allows some objects to notify other objects about changes in their state. The Observer pattern provides a way to subscribe and unsubscribe to and from these events for any object that implements a subscriber interface.
It seems that weak reference will solve your problem.
You change the observers to manage weak-references, e.g, by replacing the list
in a weakref.WeakKeyDictionary
, or by implementing some other weak-reference container. BTW, using a hashed type, such as a dictionary, will also be better than a list since removing an observer will be much more efficient.
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)
Also, it is not required to call .removeObserver(self)
in the observer's destructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With