On Sep 27, 9:23 am, George Sakkis <george.sak...@ gmail.comwrote:
On Sep 27, 1:44 am, "Dmitry S. Makovey" <dmi...@makovey .netwrote:
I guess my bias is towards more explicit declarations thus
bmethod=ProxyMe thod('b',B.bmet hod)
looks more attractive to me, but I stand to be corrected/educated why is
that not the right thing to do?
I see where you're coming from and I also prefer explicit reflection
mechanisms instead of strings (e.g. avoid eval/exec as much as
possible). As I mentioned, the second argument to ProxyMethod is (for
all sane purposes) redundant, so if you could implement it in a way
that "bmethod = ProxyMethod('b' )" worked, I would be all for it, but
AFAIK it's not possible without a metaclass.
Just for completeness, here's a metaclass version that uses
ProxyMethod declarations instead of a dict; you'll probably like this
better:
#======= usage =============== ==========
from proxies import Proxy, ProxyMethod
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::bmethod 2", 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",s elf.val, x, y
cattr = 4
class A(Proxy):
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::mymetho d",a
bmethod = ProxyMethod('b1 ')
bmethod2 = ProxyMethod('b2 ')
cmethod = ProxyMethod('c' )
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,'fo o')
A.bmethod2(a,'b ar','baz')
A.cmethod(a, 'foo')
try: A.cmethod2(a,'b ar','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 attrname,value in namespace.iteri tems():
if isinstance(valu e, ProxyMethod) and value.name is None:
value.name = attrname
return super(_ProxyMet a,meta).__new__ (meta, name, bases,
namespace)
class ProxyMethod(obj ect):
def __init__(self, proxy_attr, name=None):
self._proxy_att r = proxy_attr
self.name = name
def __get__(self, proxy, proxytype):
if proxy is not None:
return self.__get_targ et_attr(proxy)
else:
return self.__unbound_ method
def __unbound_metho d(self, proxy, *args, **kwds):
method = self.__get_targ et_attr(proxy)
return method(*args, **kwds)
def __get_target_at tr(self, proxy):
try:
delegate = getattr(proxy, self._proxy_att r)
return getattr(delegat e, self.name)
except AttributeError:
raise AttributeError( '%r object has no attribute %r' %
(proxy.__class_ _.__name__,
self.name))
class Proxy(object):
__metaclass__ = _ProxyMeta
def __init__(self, **attr2delegate ):
self.__dict__.u pdate(attr2dele gate)
#============== =============== =============== ==========
If you want to eliminate completely specifying attributes with
strings, it's easy to modify the above so that you write instead:
class A(Proxy):
...
bmethod = ProxyMethod(lam bda self: self.b1)
bmethod2 = ProxyMethod(lam bda self: self.b2)
This is more verbose for the common case, but it's more flexible in
cases where the callable may be more complex than a plain getattr().
Actually you can support both, it doesn't have to be either/or; just
check whether the argument to ProxyMethod is a callable and if not,
make it:
from operator import attrgetter
class ProxyMethod(obj ect):
def __init__(self, proxy_attr, name=None):
if not callable(proxy_ attr):
proxy_attr = attrgetter(prox y_attr)
...
Remaining Implementation is left as an exercise to the reader ;)
George