On Sep 25, 3:36 pm, "Dmitry S. Makovey" <[EMAIL PROTECTED]> wrote:
> Aaron "Castironpi" Brady wrote: > >> I kept this part of the problem out of this discussion as I'm pretty sure > >> I can fill those in once I figure out the basic problem of > >> auto-population of proxy methods since for each class/method those are > >> going to be nearly identical. If I can autogenerate those on-the-fly I'm > >> pretty sure I can add some extra-logic to them as well including > >> signature change where A::bmethod(self,c,x) would become > >> A::bmethod(self,x) etc. > > > Do you want to couple instances or classes together? > > It would be nice to have objects of B, C and D classes not knowing that they > are proxied (as they are used on their own too, not only inside of A > objects). I'm not sure if the approach below deals with all the issues, but one thing it does is decouple completely the proxied objects from the proxy: #======== usage ================================================================ from proxies import Proxy class B(object): def __init__(self): self.val = 'bval' def bmethod(self,n): print "B::bmethod",n def bmethod2(self,n,m): print "B::bmethod2",n,m class C(object): def __init__(self): self.val = 'cval' def cmethod(self,x): print "C::cmethod",x def cmethod2(self,x,y): print "C::cmethod2",x,y cattr = 4 class A(Proxy): DelegateMap = { 'bmethod' : B, 'bmethod2': B, 'cmethod': C, # do NOT delegate C.cmethod2 #'cmethod2': C, 'cattr' : C, } def __init__(self, b, c): print "init A()" # must call Proxy.__init__(*delegates) super(A,self).__init__(b,c) def amethod(self,a): print "A::mymethod",a if __name__ == '__main__': a = A(B(), C()) a.amethod('foo') # test bounded methods a.bmethod('foo') a.bmethod2('bar','baz') a.cmethod('foo') try: a.cmethod2('bar','baz') except Exception, ex: print ex # works for unbound methods too A.bmethod(a,'foo') A.bmethod2(a,'bar','baz') A.cmethod(a, 'foo') try: A.cmethod2(a,'bar','baz') except Exception, ex: print ex # non callable attributes print A.cattr #====== output ================================== init A() A::mymethod foo B::bmethod foo B::bmethod2 bar baz C::cmethod foo 'A' object has no attribute 'cmethod2' B::bmethod foo B::bmethod2 bar baz C::cmethod foo type object 'A' has no attribute 'cmethod2' 4 #======== proxies.py ========================= class _ProxyMethod(object): def __init__(self, name): self._name = name def unbound(proxy, *args, **kwds): method = proxy._get_target_attr(name) return method(*args, **kwds) self._unbound = unbound def __get__(self, proxy, proxytype): if proxy is not None: return proxy._get_target_attr(self._name) else: return self._unbound class _ProxyMeta(type): def __new__(meta, name, bases, namespace): for attrname,cls in namespace.get('DelegateMap', {}).iteritems(): if attrname not in namespace: attr = getattr(cls, attrname) if callable(attr): namespace[attrname] = _ProxyMethod(attrname) else: namespace[attrname] = attr return super(_ProxyMeta,meta).__new__(meta, name, bases, namespace) class Proxy(object): __metaclass__ = _ProxyMeta def __init__(self, *delegates): self._cls2delegate = {} for delegate in delegates: cls = type(delegate) if cls in self._cls2delegate: raise ValueError('More than one %s delegates were given' % cls) self._cls2delegate[cls] = delegate def _get_target_attr(self, name): try: cls = self.DelegateMap[name] delegate = self._cls2delegate[cls] return getattr(delegate, name) except (KeyError, AttributeError): raise AttributeError('%r object has no attribute %r' % (self.__class__.__name__, name)) HTH, George -- http://mail.python.org/mailman/listinfo/python-list