Observer-Pattern by (simple) decorator

Steven Bethard steven.bethard at gmail.com
Sat Jun 2 12:02:05 EDT 2007


David Wahler wrote:
> On Jun 2, 12:27 am, Steven Bethard <steven.beth... at gmail.com> wrote:
>> 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:
[snip]
> Is this desired behavior?
> 
>>>> a = SomeActor()
>>>> b = SomeActor()
>>>> a.meth.observers is b.meth.observers
> True
>>>> a.meth.add_callback(callback)
>>>> b.meth(42)
> 42
> Yippie, I've been called on <__main__.SomeActor object at 0x00C23550>

Yeah, I wasn't sure whether the observers were meant to be shared or 
not. Yes, they are shared in the previous code. If you don't want them 
to be shared, you can just use a WeakKeyDictionary to map instances to 
their appropriate observer lists::

 >>> class Observable(object):
...     _observer_map = weakref.WeakKeyDictionary()
...     def __init__(self, func, instance=None):
...         if instance is None:
...             observers = []
...         else:
...             observers = self._observer_map.setdefault(instance, [])
...         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)
...     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
...
 >>> a1 = SomeActor()
 >>> a2 = SomeActor()
 >>> a1.meth.observers is a2.meth.observers
False
 >>> a1.meth.add_callback(callback)
 >>> a1.meth('boring old argument')
boring old argument
Yippie, I've been called on <__main__.SomeActor object at 0x00E87890>
 >>> a2.meth('boring old argument')
boring old argument


STeVe



More information about the Python-list mailing list