import traceback from Delegator import Delegator class NamedDelegator(Delegator): "A bit of infrastructure..." def __init__(self, name): Delegator.__init__(self) self.name = name def _forward(self, to): return self.name + ' -> ' + to def _catch(self): return self.name class Catcher(NamedDelegator): "Just catches everything" forwarded = intercepted = quietly_forwarded = quietly_intercepted = \ __call__ = NamedDelegator._catch class Passer(NamedDelegator): "Just forwards everything" def forwarded(self): return self._forward(self.delegate.forwarded()) def intercepted(self): return self._forward(self.delegate.intercepted()) # forwarding quietly means letting Delegator take care of it class Interceptor(NamedDelegator): "Forwards or intercepts, according to method names" def forwarded(self): return self._forward(self.delegate.forwarded()) quietly_intercepted = NamedDelegator._catch intercepted = NamedDelegator._catch __call__ = NamedDelegator._catch class CallableDelegator(Delegator): def __call__(self, *args, **kwargs): return self.delegate.__call__(*args, **kwargs) # Set up a chain bottom = b0 = Catcher("Catcher") b1 = Passer("Passer 1") b1.setdelegate(b0) b2 = Interceptor("Interceptor 2") b2.setdelegate(b1) top = b3 = Passer("Passer 3") b3.setdelegate(b2) # See what happens print '"forwarded" is only implemented by the bottom ("Catcher"):' print 'top.forwarded() =', top.forwarded() print print 'but "intercepted" is also implemented by b2 ("Interceptor 2"):' print 'top.intercepted() =', top.intercepted() print print 'this is how it looks without printing the chains:' print 'top.quietly_forwarded() =', top.quietly_forwarded() print 'top.quietly_intercepted() =', top.quietly_intercepted() print print "now let's try something similar with __call__:" Callable = CallableDelegator() Callable.setdelegate(top) print 'Callable() =', Callable() NonCallable = Delegator() NonCallable.setdelegate(top) try: print 'NonCallable() =', NonCallable() except: print traceback.print_exc() print print 'But this works!' print 'NonCallable.delegate.__call__() =', NonCallable.delegate.__call__()