is decorator the right thing to use?

George Sakkis george.sakkis at gmail.com
Sat Sep 27 12:19:57 EDT 2008


On Sep 27, 11:27 am, George Sakkis <george.sak... at gmail.com> wrote:

> 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(lambda self: self.b1)
>     bmethod2 = ProxyMethod(lambda self: self.b2)

It's funny how often you come with a better solution a few moments
after htting send! The snippet above can (ab)use the decorator syntax
so that it becomes:

class A(Proxy):

    @ProxyMethod
    def bmethod(self):
        return self.b1

    @ProxyMethod
    def bmethod2(self):
        return self.b2

With the observation that ProxyMethod has access both to the callable
that returns the delegate and the name of the delegated method, we can
remove the need for the metaclass and the Proxy base class altogether:

class proxymethod(object):
    def __init__(self, get_delegate):
        self._get_delegate = get_delegate

    def __get__(self, proxy, proxytype):
        if proxy is not None:
            return self.__get_target_attr(proxy)
        else:
            return self.__unbound_method

    def __unbound_method(self, proxy, *args, **kwds):
        method = self.__get_target_attr(proxy)
        return method(*args, **kwds)

    def __get_target_attr(self, proxy):
        get_delegate = self._get_delegate
        try: return getattr(get_delegate(proxy),
get_delegate.__name__)
        except AttributeError:
            raise AttributeError('%r object has no attribute %r' %
                    (proxy.__class__.__name__, get_delegate.__name__))


class A(object):

    def __init__(self, b1, b2):
        self.b1 = b1
        self.b2 = b2

    def amethod(self,a):
        print "A::mymethod",a

    @proxymethod
    def bmethod(self):
        return self.b1

    @proxymethod
    def bmethod2(self):
        return self.b2


a = A(B(10), B(20))
a.amethod('foo')

print "bound proxy calls"
a.bmethod('foo')
a.bmethod2('bar','baz')

print "unbound proxy calls"
A.bmethod(a,'foo')
A.bmethod2(a,'bar','baz')

So back to the OP's original question and after a long circle.. a
decorator might well be the right thing to use after all :)

George



More information about the Python-list mailing list