[Python-Dev] Re: PEP 318: Decorators last before colon (original) (raw)

Gareth McCaughan gmccaughan at synaptics-uk.com
Mon Apr 5 12:10:42 EDT 2004


On Monday 2004-04-05 at 15:42, Andrew Koenig wrote:

Here's what I don't understand.

I imagine that most of the time, when someone decorates a function with lots of attributes, there is at least the possibility of decorating more than one function with the same set of attributes. In such a case, doesn't it make sense to bind a variable to the attributes and use it instead? Attributes = [staticmethod, classmethod, otherattributes(debug=True)] def foo(bar, baz) Attributes: pass And doesn't this idea answer the objection that too many attributes after the parameter list make the definition hard to read?

It certainly answers that objection, but it has (so it seems to me) other problems of its own; see below.

For that matter, why do we need the brackets if there is only one attribute:

def foo(bar, baz) staticmethod: pass I am suggesting that what comes between the ) and the : should be an expression, which must evaluate to either a callable or a sequence of callables. For that matter, why not allow a tuple expression without parentheses: def foo(bar, baz) staticmethod, classmethod: pass Whatever sequence you put there, I think the semantics are clear: Before binding a name to the function, pass it to the callable or in turn to each element of the sequence.

The brackets serve multiple purposes.

Omitting them breaks all these things, especially if an arbitrary expression is allowed there. And do we really want to allow

def foo(bar, baz) quux(wibble, spong):
    pass

That's not a hideous pathological case; it's what a simple decoration using a parameterized decorator will look like without the brackets. With good decorator names I suppose it becomes somewhat comprehensible:

def foo(bar, baz) memoized(25):
    pass

but surely it's still much clearer when written as

def foo(bar, baz) [memoized(25)]:
    pass

or even (though I'm a little tempted to agree with whoever it was that was wondering whether Guido has been abducted by aliens)

[memoized(25)]
def foo(bar, baz):
    pass

We can keep the syntactic distinctiveness while still allowing multiple decorators to be combined, by having a function (a builtin, perhaps, but it's not hard to write) that composes decorators:

def compose(*decorators):
    def _(f):
        for d in decorators: f = d(f)
        return f

our_attributes = compose(staticmethod, classmethod,
  otherattributes(debug=True))

def foo(bar, baz) [our_attributes]:
    pass

-- Gareth McCaughan



More information about the Python-Dev mailing list