is decorator the right thing to use?

Aaron "Castironpi" Brady castironpi at gmail.com
Thu Sep 25 20:50:30 CEST 2008


On Sep 25, 1:22 pm, "Dmitry S. Makovey" <dmi... at athabascau.ca> wrote:
> Aaron "Castironpi" Brady wrote:
> > You should write it like this:
>
> > class B(object):
> >      @A.proxy
> >      def bmethod(self,a):
>
> > Making 'proxy' a class method on A.  
>
> makes sense.
>
> > In case different A instances (do
> > you have more than one BTW?)
>
> yep. I have multiple instances of class A, each one has properties (one per
> class) of classes B, C and D:
>
> class A:
>         b=None
>         c=None
>         d=None
>         def __init__(self,b,c,d):
>                 self.b=b
>                 self.c=c
>                 self.d=d
>
>         ...magic with proxying methods goes here...
>
> class B:
>         def bmethod(self,x): pass # we proxy this method from A
>         def bmethod2(self,x): pass # this is not proxied
> class C:
>         def cmethod(self,x): pass # we proxy this method from A
> class D:
>         def dmethod(self,x): pass # we proxy this method from A
>
> a=A(B(),C(),D())
> x='foo'
> a.bmethod(x)
> a.cmethod(x)
> a.dmethod(x)
> a.bmethod2(x) # raises error as we shouldn't proxy bmethod2
>
> above is the ideal scenario.
>
> > What you've said implies that you only have one B instance, or only
> > one per A instance.  Is this correct?
>
> yes. as per above code.
>
> > I agree that __setattr__ is the canonical solution to proxy, but you
> > have stated that you want each proxied method to be a member in the
> > proxy class.
>
> well. kind of. if I can make it transparent to the consumer so that he
> shouldn't do:
>
> a.b.bmethod(x)
>
> but rather:
>
> a.bmethod(x)
>
> As I'm trying to keep b, c and d as private properties and would like to
> filter which calls are allowed to those. Plus proxied methods in either one
> always expect certain parameters like:
>
> class B:
>         def bmethod(self,c,x): pass
>
> and A encapsulates 'c' already and can fill in that blank automagically:
>
> class A:
>         c=None
>         b=None
>         def bmethod(self,c,x):
>                 if not c:
>                         c=self.c
>                 b.bmethod(self,c,x)
>
> I kept this part of the problem out of this discussion as I'm pretty sure I
> can fill those in once I figure out the basic problem of auto-population of
> proxy methods since for each class/method those are going to be nearly
> identical. If I can autogenerate those on-the-fly I'm pretty sure I can add
> some extra-logic to them as well including signature change where
> A::bmethod(self,c,x) would become A::bmethod(self,x) etc.

Do you want to couple instances or classes together?

If A always proxies for B, C, and D, then the wrapper solution isn't
bad.  If you're going to be doing any instance magic, that can change
the solution a little bit.

There's also a revision of the first implementation of Aproxy you
posted, which could stand alone as you have it, or work as a
classmethod or staticmethod.

> 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

def Aproxy(fn):
    def delegate(self,*args,**kw):
        print "%s::%s" % (args[0].__class__.__name__,fn.__name__)
        fnew=getattr(self.b,fn.__name__)
        return fnew(*args,**kw)
    setattr(A,fn.__name__,delegate)
    return fn



More information about the Python-list mailing list