
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. - They make the decoration *look*, even to novice eyes, like an annotation: "by the way, please make this a static method". - They may possibly help the parser a little. (I'm showing my ignorance here; I haven't really looked at the Python parser at all.) - They give a hint to the user that what goes in between them may be a sequence, not just a single item. - They ensure that all decorated definitions have a somewhat consistent appearance. 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