is decorator the right thing to use?

showellshowell at gmail.com showellshowell at gmail.com
Wed Sep 24 22:08:04 EDT 2008


On Sep 24, 3:21 pm, "Dmitry S. Makovey" <dmi... at athabascau.ca> wrote:
> Hi,
>
> after hearing a lot about decorators and never actually using one I have
> decided to give it a try. My particular usecase is that I have class that
> acts as a proxy to other classes (i.e. passes messages along to those
> classes) however hand-coding this type of class is rather tedious, so I
> decided to use decorator for that. Can somebody tell me if what I'm doing
> is a potential shot-in-the-foot or am I on the right track? (Note, It's
> rather rudimentary proof-of-concept implementation and not the final
> solution I'm about to employ so there are no optimizations or
> signature-preserving code there yet, just the idea).
>

Your code below is very abstract, so it's kind of hard to figure out
what problem you're trying to solve, but it seems to me that you're
using the B proxy class to decorate the A target class, which means
you want one of these options:

  1) Put decorators over the methods in A, not B.  Isn't it the
methods of A that are being decorated here?

  2) Eliminate the decorator syntax and make your code more
expressive:

 a = SomeClass()
 # first call it directly
 x = a.foo()
 y = a.bar()
 # now decorate it
 debug_proxy =
ClassThatDecoratesMethodCallsToObjectWithDebuggingCode(a)
 debug_proxy.decorate_methods('foo', 'bar')

The decorate_methods method would be magical, in terms of overwriting
a's innards, while still preserving the same interface for its users.

But again, I'm just guessing here, because it's hard to know what
problem you're really solving.

Cheers,

Steve

Code quoted below:
> Here's the code:
>
> class A:
>     b=None
>     def __init__(self,b):
>         self.val='aval'
>         self.b=b
>         b.val='aval'
>
>     def mymethod(self,a):
>         print "A::mymethod, ",a
>
>     def mymethod2(self,a):
>         print "A::another method, ",a
>
> def Aproxy(fn):
>     def delegate(*args,**kw):
>         print "%s::%s" % (args[0].__class__.__name__,fn.__name__)
>         args=list(args)
>         b=getattr(args[0],'b')
>         fnew=getattr(b,fn.__name__)
>         # get rid of original object reference
>         del args[0]
>         fnew(*args,**kw)
>     setattr(A,fn.__name__,delegate)
>     return fn
>
> class B:
>     def __init__(self):
>         self.val='bval'
>
>     @Aproxy
>     def bmethod(self,a):
>         print "B::bmethod"
>         print a, self.val
>
>     @Aproxy
>     def bmethod2(self,a):
>         print "B::bmethod2"
>         print a, self.val
>
> b=B()
> b.bmethod('foo')
> a=A(b)
> b=B()
> b.val='newval'
> a.bmethod('bar')
> a.bmethod2('zam')




More information about the Python-list mailing list