is decorator the right thing to use?
Dmitry S. Makovey
dmitry at athabascau.ca
Thu Sep 25 11:47:51 EDT 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