Re: is decorator the right thing to use?



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
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
^^^^^^ you don't need this

    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
.



Relevant Pages

  • Re: is decorator the right thing to use?
    ... auto-population of proxy methods since for each class/method those are ... # do NOT delegate C.cmethod2 ... A::mymethod foo ... if cls in self._cls2delegate: ...
    (comp.lang.python)
  • Re: smart pointer dangerous (no -> operator)
    ... So Ada provides only two ways to access the managed object? ... In Ada 95 I declare the proxy type tagged controlled. ... The implementation of Foo goes as follows: ... the target object is derived from Object.Entity. ...
    (comp.lang.ada)
  • Re: is decorator the right thing to use?
    ... ProxyMethod declarations instead of a dict; ... from proxies import Proxy, ProxyMethod ... bmethod = ProxyMethod ... B::bmethod 10 foo ...
    (comp.lang.python)
  • X11 forwarding over proxied connection.
    ... I can do "ssh -X foo" where foo is a local machine on the same network and ... I assume this has something to do with the proxy. ...
    (comp.security.ssh)
  • Re: DECnet V proxy problem...
    ... From nodes NOT HERE;) I have no problem with proxy access. ... VAXman- A Bored Certified VMS Kernel Mode Hacker    VAXmanTMESISORG ... I'd look at the format of the intrusion records and note any that have ...
    (comp.os.vms)