is decorator the right thing to use?

Dmitry S. Makovey dmitry at athabascau.ca
Thu Sep 25 17:47:51 CEST 2008


Thanks Bruno,

your comments were really helpful (so was the "improved" version of code). 

My replies below:

Bruno Desthuilliers wrote:
>> So decorators inside of B just identify that those methods will be
>> proxied by A. On one hand from logical standpoint it's kind of weird to
>> tell class that it is going to be proxied by another class,
> 
> Indeed - usually, proxied objects shouldn't have to be aware of the
> fact. That doesn't mean your variation on the proxy pattern is
> necessarily bad design (hard to tell without lot of context anyway...),
> but still there's some alarm bell ringing here IMHO - IOW : possibly the
> right thing to do, but needs to be double-checked.

I'm kind of looking at options and not dead-set on decorators, but I can't
find any other "elegant enough" solution which wouldn't lead to such tight
coupling. The problem I'm trying to solve is not much more complicated than
what I have already described so if anybody can suggest a better approach -
I'm all for it. 

> Now I'm not sure I really like your implementation. Here's a possible
> rewrite using a custom descriptor:

yeah, that was going to be my next step - I was just aiming for
proof-of-concept more then efficient code :)

> class Proxymaker(object):
>      def __init__(self, attrname):
>          self.attrname = attrname
> 
>      def __get__(self, instance, cls):
>          def _proxied(fn):
>              fn_name = fn.__name__
>              def delegate(inst, *args, **kw):
>                  target = getattr(inst, self.attrname)
>                  #return fn(target, *args,**kw)
>                  method = getattr(target, fn_name)
>                  return method(*args, **kw)
> 
>              delegate.__name__ = "%s_%s_delegate" % \
>                  (self.attrname, fn_name)
> 
>              setattr(cls, fn_name, delegate)
>              return fn
> 
>          return _proxied
> 
> class A(object):
>      def __init__(self,b):
>          self.val='aval'
>          self.b=b
>          b.val='aval'
> 
>      proxy2b = Proxymaker('b')
> 
>      def mymethod(self,a):
>          print "A::mymethod, ",a
> 
>      def mymethod2(self,a):
>          print "A::another method, ",a
> 
> class B(object):
>      def __init__(self):
>          self.val='bval'
> 
>      @A.proxy2b
>      def bmethod(self,a):
>          print "B::bmethod"
>          print a, self.val
> 
>      @A.proxy2b
>      def bmethod2(self,a):
>          print "B::bmethod2"
>          print a, self.val

> My point is that:
> 1/ you shouldn't have to rewrite a decorator function - with basically
> the same code - for each possible proxy class / attribute name pair combo
> 2/ making the decorator an attribute of the proxy class makes
> dependencies clearer (well, IMHO at least).

agreed on all points

> I'm still a bit uneasy wrt/ high coupling between A and B, and if I was
> to end up with such a design, I'd probably take some times to be sure
> it's really ok.

that is the question that troubles me at this point - thus my original post
(read the subject line ;) ). I like the clarity decorators bring to the
code and the fact that it's a solution pretty much "out-of-the-box" without
need to create something really-really custom, but I'm worried about tight
coupling and somewhat backward logic that they would introduce (the way I
envisioned them).





More information about the Python-list mailing list