How do I write a program with observer/ observable facilities in Python as in Java? I'd write something like following in Java.
import java.util.Observable;
import java.util.Observer;
public class ObservDemo extends Object {
MyView view;
MyModel model;
public ObservDemo() {
view = new MyView();
model = new MyModel();
model.addObserver(view);
}
public static void main(String[] av) {
ObservDemo me = new ObservDemo();
me.demo();
}
public void demo() {
model.changeSomething();
}
/** The Observer normally maintains a view on the data */
class MyView implements Observer {
/** For now, we just print the fact that we got notified. */
public void update(Observable obs, Object x) {
System.out.println("update(" + obs + "," + x + ");");
}
}
/** The Observable normally maintains the data */
class MyModel extends Observable {
public void changeSomething() {
// Notify observers of change
setChanged();
notifyObservers();
}
}
}
(This code is take from the following link http://www.java2s.com/Code/Java/Design-Pattern/AsimpledemoofObservableandObserver.htm )
how do I accomplish in such thing in Python?
First of all, as Martijn Pieters said, Python is not Java. This means that probably you don't need the whole observer/observed pattern, but can boil it down to a more simplified version. In the end I will show something a little more pythonesque, but to remain to a very basic java implementation, you can try something like this:
class Observer(object):
def notify(self,*args,**kwargs):
print args,kwargs
class Target(object):
def __init__(self,*observers):
self.observes = observers
#this notify for every access to the function
def event(self,data):
for obs in self.observes:
obs.notify('event',data)
print "event with",data
t = Target(Observer())
t.event(1)
#('event', 1) {}
#event with 1
otherwise you can implement it with a decorator, that is quite similar:
def observe(f):
def decorated(self,*args,**kwargs):
for obs in self.observes:
obs.notify('event',*args,**kwargs)
return f(self,*args,**kwargs)
return decorated
class Target(object):
def __init__(self,*observers):
self.observes = observers
@observe
def otherevent(self,data):
print "other event with",data
Now, all these methods works, but they are not very pythonic. The best way that comes to mind to implement something like this in a pythonic way is to implement a wrapper that check for attribute access and call a callback function (that can be the notify function of the observer, but it's a more general approach)
class Wrapper(object):
def __init__(self,wrapped,*callbacks):
self.wrapped = wrapped
self.callbacks = callbacks
def __getattr__(self,name):
res = self.wrapped.__getattribute__(name)
if not callable(res):
return res
def wrap(*args,**kwargs):
for c in self.callbacks:
c(self.wrapped,f,*args,**kwargs)
return res(*args,**kwargs)
return wrap
def __str__(self):
return self.wrapped.__str__()
#in this example I will keep a record of each call performed on a list
called = []
#this is the list
a = []
#and this is the wrapped list
w = Wrapper(a,lambda f,v,ign: called.append((f,v)) )
#I append an element to the wrapper
w.append(1)
#and I can see that it modify the original list
print a
#the print of the wrapped is well behaved, having defined the __str__ function
print w
#and we can see which function we called and which were the parameters
print called
This approach is alittle more convoluted, as you have to redirect manually all the magic methods, but is way more powerful as allow to implement the observer pattern to any kind of object, attaching to it any compatible function, without the need to specify a generic class of observes. There are ways to automaticaly redirect all the magic function calls, but it's a little complicated and will just confuse the main point
The fastest you forget about java when working in python, the more fun it will get. I suggest you to read this piece:
http://dirtsimple.org/2004/12/python-is-not-java.html
good luck with your work!
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