[Python-Dev] Re: PEP 318: Decorators last before colon
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.
- 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
More information about the Python-Dev
mailing list