[Python-ideas] Decorator syntax restriction

Paul Moore p.f.moore at gmail.com
Fri Oct 2 14:18:03 CEST 2009


2009/10/2 Rob Cliffe <rob.cliffe at btinternet.com>:
> So: please speak, if you agree with me, whether for the reasons I give or
> for different ones, or if you disagree with me - please give reasons too.

I believe that the key reason for there being restrictions is to avoid
Python code looking like "line noise". That's not precise - the
specific rules as given express a sensible (in my view) balance
between this goal and simplicity of
implementation/explanation/usability.

For example, without restrictions the following would be valid (yes,
it's silly, yes it's deliberately a worst case)

@(a['b'].fns[1])(1,2,{3,4})
def something():

I contend that's clearly "line noise". Python has a long tradition of
not just frowning on code like this, but actively forbidding such code
and not implementing constructs that contribute to such. Witness the
fact that C's ternary operator (?:) and the pre and post increment
operators (++ and --) are not valid Python. So forbidding such code is
clearly consistent with Python's traditions.

@classmethod
def f(...):

is equally obviously *not* line noise, and it's entirely reasonable to
allow it. So pick a point on the spectrum between the first and second
example. That's what the current rules do - you may not agree with the
precise point picked, but my contention is that not picking a point at
all is contrary to Python's established design.

I'm not sure there is a corresponding design principle within Python
that all constructs should be fully general (which is basically the
principle you're appealing to). I can't immediately find
counterexamples, though, so there may be a point there. But certainly,
I'd say that such a principle (if it exists) isn't as well-established
as the "no line noise" one (witness comments like "if you want Perl,
you know where to get it"...)

> 1(a)) It was inconsistent to impose a restriction on expressions in one particular context [meaning: and not in others].
> 1(b)) The restriction was hard to explain [but see below].
> 2) The restriction can easily be circumvented.
> 3) Plausible use cases exist [I gave some].

The above covers my feelings on 1(a) and 1(b).

With regard to (2), circumventing the restriction isn't really the
point - the whole decorator construct is a shorthand.

@deco
def fn():
    ...

vs

def fn():
    ...
fn = deco(fn)

Giving a complex expression a name increases readability, and the
assignment can be kept near the decorator if it's a one-off, as
follows

meaningful_name = (a['b'].fns[1])(1,2,{3,4})

@meaningful_name
def f():
    ...

I'd go so far as to say that was improving readability, rather than
"circumvention".

As for (3), I agree that plausible use cases exist. They *may* warrant
allowing certain extra constructs in ("moving the point" as I said
above) but I'm not sure about that, and to my mind they certainly
don't warrant completely removing the restriction.

As a final point, I should say that personally, I have never written
any code which is impacted by the current restrictions on decorator
syntax. So, I don't personally have any need for the relaxation you're
proposing. I'm not sure if that's a point in your favour (as my view
is of limited value since I don't need the feature you're proposing)
or against (as I'm an example of why the proposal isn't as generally
useful as you claim) but I mention it anyway, in the interests of
complete disclosure :-)

I hope this helps.

Paul.



More information about the Python-ideas mailing list