PEP 318: Is chaining decorators even possible?

Ian Bicking ianb at colorstudy.com
Thu Jun 12 16:17:05 EDT 2003


On Thu, 2003-06-12 at 07:03, Kevin Smith wrote:
> It has been brought up a couple of times in other threads that simply 
> chaining descriptors won't work (i.e. classmethod(synchronized(foo))).  
> Another possibility was to use subclassing (i.e. type('newtype',(
> classmethod,synchronized,{})(foo)).  When I wrote PEP 318, I wasn't sure 
> myself if it was possible to chain them, but I figured someone would 
> point it out if it wasn't.  So my question is, is it even possible to 
> chain decorators in a general way?  If not, then PEP 318 might have to 
> be changed to only allow one decorator.  This would definitely reduce 
> the amount of discussion since the proposed syntax would be reduced to 
> 'def foo(self) as <callable>:'.

The chaining seems to only be a problem with decorators that create
descriptors.  I'd imagine synchronized being implemented something like:

def synchronized(lock):
    def wrapper(func):
        return SynchronizedFunction(func, lock).call
    return wrapper

class SynchronizedFunction(object):

    def __init__(self, func, lock):
        self.func = func
        self.lock = lock

    def call(self, *args, **kw):
        self.lock.acquire()
        value = self.func(*args, **kw)
        self.lock.release()
        return value

A contract system would probably work similarly.  It doesn't produce a
descriptor, it just wraps the function call.  Of course, "func" can't be
a descriptor, or it would mess things up.  Unfortunately this doesn't
really work quite right, as it returns a method object, and not a
function object, and classes have a special case of turning functions
into methods.

So I guess a proper implementation of Synchronized would either have to
use nested scopes (to bind func and lock), or create a descriptor.

Maybe:

def synchronized(lock):
    def wrapper(func):
        def wrappedfunc(*args, **kw):
            lock.acquire()
            value = func(*args, **kw)
            lock.release()
            return value
        return wrappedfunc
    return wrapper

But objects would certainly be more comfortable, especially for
something more complex like contracts.

  Ian







More information about the Python-list mailing list