Re: is decorator the right thing to use?
- From: George Sakkis <george.sakkis@xxxxxxxxx>
- Date: Fri, 26 Sep 2008 18:57:10 -0700 (PDT)
On Sep 26, 6:38 pm, "Dmitry S. Makovey" <dmi...@xxxxxxxxxxxxx> wrote:
I actually ended up rewriting things (loosely based on George's suggested
code) with descriptors and not using metaclasses or decorators (so much for
my desire to use them).
With following implementation (unpolished at this stage but already
functional) I can have several instances of B objects inside of A object
and proxy certain methods to one or another object (I might be having a
case when I have A.b1 and A.b2 and passing some methods to b1 and others to
b2 having both of the same class B, maybe even multiplexing).
You seem to enjoy pulling the rug from under our feet by changing the
requirements all the time :)
This one^^^^^^ you don't need this
seems to be fairly light as well without need to scan instances (well,
except for one getattr, but I couldn't get around it). Maybe I didn't
account for some shoot-in-the-foot scenarios but I can't come up with any..
Last time I played with __getattr__ I shot myself in the foot quite well
BTW :)
[code snipped]
class A:
b=None
def __init__(self,b=None):
self.val='aval'
self.b=b
b.val='aval-b'
def mymethod(self,a):
print "A::mymethod, ",a
bmethod = ProxyMethod('b',B.bmethod)
Although this works, the second argument to ProxyMethod shouldn't be
necessary, it's semantically redundant; ideally you would like to
write it as "bmethod = ProxyMethod('b')". As before, I don't think
that's doable without metaclasses (or worse, stack frame hacking).
Below is the update of my original recipe; interestingly, it's
(slightly) simpler than before:
#======= usage ========================================
from proxies import Proxy
class B(object):
def __init__(self, val): self.val = val
def bmethod(self,n): print "B::bmethod", self.val, n
def bmethod2(self,n,m): print "B::bmethod2", self.val, n, m
class C(object):
def __init__(self, val): self.val = val
def cmethod(self,x): print "C::cmethod", self.val, x
def cmethod2(self,x,y): print "C::cmethod2",self.val, x, y
cattr = 4
class A(Proxy):
# DelegateMap:
# Maps each delegate method to the proxy attribute that refers to
the
# respective delegate object
DelegateMap = {
'bmethod' : 'b1',
'bmethod2': 'b2',
'cmethod' : 'c',
# do NOT delegate C.cmethod2
#'cmethod2': 'c',
}
def __init__(self, b1, b2, c):
print "init A()"
# must call Proxy.__init__
super(A,self).__init__(b1=b1, b2=b2, c=c)
def amethod(self,a):
print "A::mymethod",a
if __name__ == '__main__':
a = A(B(10), B(20), C(30))
a.amethod('foo')
print "bound proxy calls"
a.bmethod('foo')
a.bmethod2('bar','baz')
a.cmethod('foo')
try: a.cmethod2('bar','baz')
except Exception, ex: print ex
print "unbound proxy calls"
A.bmethod(a,'foo')
A.bmethod2(a,'bar','baz')
A.cmethod(a, 'foo')
try: A.cmethod2(a,'bar','baz')
except Exception, ex: print ex
#======= output ========================================
init A()
A::mymethod foo
bound proxy calls
B::bmethod 10 foo
B::bmethod2 20 bar baz
C::cmethod 30 foo
'A' object has no attribute 'cmethod2'
unbound proxy calls
B::bmethod 10 foo
B::bmethod2 20 bar baz
C::cmethod 30 foo
type object 'A' has no attribute 'cmethod2'
#====== proxies.py ======================================
class _ProxyMeta(type):
def __new__(meta, name, bases, namespace):
for methodname in namespace.get('DelegateMap', ()):
if methodname not in namespace:
namespace[methodname] = _ProxyMethod(methodname)
return super(_ProxyMeta,meta).__new__(meta, name, bases,
namespace)
class _ProxyMethod(object):
def __init__(self, name):
self._name = name
def __get__(self, proxy, proxytype):
if proxy is not None:
return proxy._get_target_attr(self._name)
else:
return self._unbound_method
def _unbound_method(self, proxy, *args, **kwds):
method = proxy._get_target_attr(self._name)
return method(*args, **kwds)
class Proxy(object):
__metaclass__ = _ProxyMeta
def __init__(self, **attr2delegate):
self.__dict__.update(attr2delegate)
def _get_target_attr(self, name):
try:
delegate = getattr(self, self.DelegateMap[name])
return getattr(delegate, name)
except (KeyError, AttributeError):
raise AttributeError('%r object has no attribute %r' %
(self.__class__.__name__, name))
HTH,
George
.
- Follow-Ups:
- Re: is decorator the right thing to use?
- From: Dmitry S. Makovey
- Re: is decorator the right thing to use?
- References:
- is decorator the right thing to use?
- From: Dmitry S. Makovey
- Re: is decorator the right thing to use?
- From: showellshowell@xxxxxxxxx
- Re: is decorator the right thing to use?
- From: Dmitry S. Makovey
- Re: is decorator the right thing to use?
- From: Dmitry S. Makovey
- Re: is decorator the right thing to use?
- From: Diez B. Roggisch
- Re: is decorator the right thing to use?
- From: Dmitry S. Makovey
- Re: is decorator the right thing to use?
- From: Paul McGuire
- Re: is decorator the right thing to use?
- From: Dmitry S. Makovey
- Re: is decorator the right thing to use?
- From: Bruno Desthuilliers
- Re: is decorator the right thing to use?
- From: Dmitry S. Makovey
- is decorator the right thing to use?
- Prev by Date: Re: Time.sleep(0.0125) not available within Linux
- Next by Date: Re: Not fully OO ?
- Previous by thread: Re: is decorator the right thing to use?
- Next by thread: Re: is decorator the right thing to use?
- Index(es):
Relevant Pages
|