Observer-Pattern by (simple) decorator

Steven Bethard steven.bethard at gmail.com
Fri Jun 1 19:27:10 EDT 2007


Wildemar Wildenburger wrote:
> I thought: I'll just write a decorator that lets me react to method 
> calls easily (the ever so popular observer-pattern). I've looked at some 
> recepies, but I just don't get them (I'm feeling kinda dumb today, sorry).
[snip]
> This is more complicated than expected mainly for two reasons:
> 
>    * I can't find a way to pass the proper 'instance' argument to
>      callback, that is, I don't know how to retrieve the instance that
>      meth() was called on, because the observable decorator only gets
>      the *function* object but not the *method*. (I hope this was clear
>      enough)
>    * Also, I don't see how I could add the add_callback() method to the
>      meth object. That doesn't seem possible. I can add it to meth's
>      function object just fine in the definition of observable, but I
>      thats not what I really want. This is probably just a cosmetic
>      issue because I don't like the idea of calling
>      sa.meth.im_func.add_callback(callback).


I think you want to define __get__ on your Observable class so that it 
can do the right thing when the method is bound to the instance:

 >>> class Observable(object):
...     def __init__(self, func, instance=None, observers=None):
...         if observers is None:
...             observers = []
...         self.func = func
...         self.instance = instance
...         self.observers = observers
...     def __get__(self, obj, cls=None):
...         if obj is None:
...         	return self
...         else:
...         	func = self.func.__get__(obj, cls)
...         	return Observable(func, obj, self.observers)
...     def __call__(self, *args, **kwargs):
...         result = self.func(*args, **kwargs)
...         for observer in self.observers:
...             observer(self.instance)
...         return result
...     def add_callback(self, callback):
...         self.observers.append(callback)
...
 >>> class SomeActor(object):
...     @Observable
...     def meth(self, foo):
...         print foo
...
 >>> def callback(instance):
...     print "Yippie, I've been called on", instance
...     instance.bar = True
...
 >>> sa = SomeActor()
 >>> sa.meth.add_callback(callback)
 >>> sa.meth("I'm the boring old argument")
I'm the boring old argument
Yippie, I've been called on <__main__.SomeActor object at 0x00E7A4D0>
 >>> sa.bar
True


STeVe



More information about the Python-list mailing list