Allow arbitrary expressions in decorator syntax

The current grammar for decorators is decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE This restricts the decorator syntax to dotted names with an optional call with an argument list: @spam.eggsdef f(): ... @ham('foo, 'bar')def g(): ... I love the amount of generality and abstraction in Python, but I think this is a place where there could be more of that: I think arbitrary expressions should be allowed; the value of that expression is what gets used as the decorator, using its *call* method (raising TypeError if the object is not callable). This would allow things like: @(lambda x: x)def f(): ... (this currently raises a SyntaxError). Note that I didn’t come up with this because I have a particular application in mind, it just irks me that this isn’t possible in Python :-) ! Here is a perhaps slightly more stimulating example: @(lambda factory: factory())def foo(): # this is a one-use factory for real_foo call_count = 0 # essentially a static variable def real_foo(): nonlocal call_count call_count += 1 return call_count return real_foo This is more a “purity” thing than a “practicality” thing, but I don’t think it has any negative effects on practicality or on the usual use of decorators.

On Sat, Sep 19, 2020 at 4:35 AM Paolo Lammens <lammenspaolo@gmail.com> wrote:
Guido's Time Machine has been deployed and this change has already been made! https://www.python.org/dev/peps/pep-0614/ Starting with Python 3.9 (due for GA release in about a month), decorator syntax WILL be more flexible! :) ChrisA

Don't worry, I've got you covered: https://www.python.org/dev/peps/pep-0614/ Look for it when Python 3.9 drops in a couple of weeks! Brandt

Great! I've just read the PEP, and the new grammar is just decorator: '@' namedexpr_test NEWLINE with the only parentheses requirement being tuple displays. Does that mean that the following is valid? class Spam: def __add__(self, other): return self def __call__(self, f): return f @ Spam() + Spam() def func(): pass That looks hella weird XD

On Fri, Sep 18, 2020 at 3:50 PM Paolo Lammens <lammenspaolo@gmail.com> wrote:
I think so, yes.
That looks hella weird XD
Indeed it does, but you can do all kinds of other "weird" stuff with callables -/ they are objects like any other, and this can be the result of virtually any expression. -CHB
-- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython -- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

I was referring more to the fact that you don't need parentheses around that—if I remove the leading space, it looks like @ is an operator that operates on the first `Spam()`: @Spam() + Spam() def func() pass while instead it's just part of the (compound) statement syntax for function definition. If one had to think of @ as an operator, it would be a unary operator of the absolute lowest priority. So, from a code style perspective, should we add a space between it and the expression? This should be discussed and added to PEP8, it's a very transcendental matter! ;) On Sat, 19 Sep 2020, 03:45 Christopher Barker, <pythonchb@gmail.com> wrote:

I also wanted to add: If @a, b, c def func(): ... was prohibited (i.e. you must use parentheses) because [it looks like] it doesn't make any sense, shouldn't be also the case that any expression with spaces should be parenthesized? Because this looks equally "wrong": @a + b * c**d % e def func(): pass Granted, there is no rule resembling this anywhere else in Python, but maybe an exception can be made here, to keep it consistent with the above? On Sat, 19 Sep 2020, 03:53 Paolo Lammens, <lammenspaolo@gmail.com> wrote:

On Sat, 19 Sep 2020 at 04:06, Paolo Lammens <lammenspaolo@gmail.com> wrote:
I didn't really follow the discussions on the PEP that relaxed the rules, but I'd say that the current (restrictive) rules were there to avoid people using "weird" stuff as decorators. The relaxation allows more flexibility, but at the cost of allowing people to do weird stuff. So let's just tell people not to do that - there's not much point in trying to define a *different* rule for "useful but not weird stuff" IMO. The rationale in the PEP may have a better explanation - if you haven't already, I'd suggest you read it and see if it helps clarify things for you. Paul

Please stop arguing. On Fri, Sep 18, 2020 at 20:07 Paolo Lammens <lammenspaolo@gmail.com> wrote:
No, It is because tulles aren’t callable. So it CANNOT have a meaning. shouldn't be also the case that any expression with spaces should be
A set of overloads could be devised to make this do something useful.
Granted, there is no rule resembling this anywhere else in Python, but maybe an exception can be made here, to keep it consistent with the above?
What consistency? The consistent rule is that the grammar doesn’t judge what users want to do with the language. -- --Guido (mobile)

Please stop arguing.
As far as I'm concerned, we weren't. :)
No, It is because tulles aren’t callable. So it CANNOT have a meaning.
True, I realized that only after I sent it.
The consistent rule is that the grammar doesn’t judge what users want to do with the language.
Maybe I expressed myself incorrectly. I am in no way saying that this shouldn't be allowed—on the contrary: I'm the first to say that the grammar shouldn't judge what users want to do with the language (Python's flexibility is one of the main aspects I love about it, if not *the* main aspect). I want that to be 100% valid Python. I was just saying, from a code style perspective, it would be sensible to always parenthesize constructs of the sort: @(a + b * c**d % e) def func(): pass On Sat, 19 Sep 2020 at 15:41, Guido van Rossum <guido@python.org> wrote:

On Sat, Sep 19, 2020 at 4:35 AM Paolo Lammens <lammenspaolo@gmail.com> wrote:
Guido's Time Machine has been deployed and this change has already been made! https://www.python.org/dev/peps/pep-0614/ Starting with Python 3.9 (due for GA release in about a month), decorator syntax WILL be more flexible! :) ChrisA

Don't worry, I've got you covered: https://www.python.org/dev/peps/pep-0614/ Look for it when Python 3.9 drops in a couple of weeks! Brandt

Great! I've just read the PEP, and the new grammar is just decorator: '@' namedexpr_test NEWLINE with the only parentheses requirement being tuple displays. Does that mean that the following is valid? class Spam: def __add__(self, other): return self def __call__(self, f): return f @ Spam() + Spam() def func(): pass That looks hella weird XD

On Fri, Sep 18, 2020 at 3:50 PM Paolo Lammens <lammenspaolo@gmail.com> wrote:
I think so, yes.
That looks hella weird XD
Indeed it does, but you can do all kinds of other "weird" stuff with callables -/ they are objects like any other, and this can be the result of virtually any expression. -CHB
-- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython -- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

I was referring more to the fact that you don't need parentheses around that—if I remove the leading space, it looks like @ is an operator that operates on the first `Spam()`: @Spam() + Spam() def func() pass while instead it's just part of the (compound) statement syntax for function definition. If one had to think of @ as an operator, it would be a unary operator of the absolute lowest priority. So, from a code style perspective, should we add a space between it and the expression? This should be discussed and added to PEP8, it's a very transcendental matter! ;) On Sat, 19 Sep 2020, 03:45 Christopher Barker, <pythonchb@gmail.com> wrote:

I also wanted to add: If @a, b, c def func(): ... was prohibited (i.e. you must use parentheses) because [it looks like] it doesn't make any sense, shouldn't be also the case that any expression with spaces should be parenthesized? Because this looks equally "wrong": @a + b * c**d % e def func(): pass Granted, there is no rule resembling this anywhere else in Python, but maybe an exception can be made here, to keep it consistent with the above? On Sat, 19 Sep 2020, 03:53 Paolo Lammens, <lammenspaolo@gmail.com> wrote:

On Sat, 19 Sep 2020 at 04:06, Paolo Lammens <lammenspaolo@gmail.com> wrote:
I didn't really follow the discussions on the PEP that relaxed the rules, but I'd say that the current (restrictive) rules were there to avoid people using "weird" stuff as decorators. The relaxation allows more flexibility, but at the cost of allowing people to do weird stuff. So let's just tell people not to do that - there's not much point in trying to define a *different* rule for "useful but not weird stuff" IMO. The rationale in the PEP may have a better explanation - if you haven't already, I'd suggest you read it and see if it helps clarify things for you. Paul

Please stop arguing. On Fri, Sep 18, 2020 at 20:07 Paolo Lammens <lammenspaolo@gmail.com> wrote:
No, It is because tulles aren’t callable. So it CANNOT have a meaning. shouldn't be also the case that any expression with spaces should be
A set of overloads could be devised to make this do something useful.
Granted, there is no rule resembling this anywhere else in Python, but maybe an exception can be made here, to keep it consistent with the above?
What consistency? The consistent rule is that the grammar doesn’t judge what users want to do with the language. -- --Guido (mobile)

Please stop arguing.
As far as I'm concerned, we weren't. :)
No, It is because tulles aren’t callable. So it CANNOT have a meaning.
True, I realized that only after I sent it.
The consistent rule is that the grammar doesn’t judge what users want to do with the language.
Maybe I expressed myself incorrectly. I am in no way saying that this shouldn't be allowed—on the contrary: I'm the first to say that the grammar shouldn't judge what users want to do with the language (Python's flexibility is one of the main aspects I love about it, if not *the* main aspect). I want that to be 100% valid Python. I was just saying, from a code style perspective, it would be sensible to always parenthesize constructs of the sort: @(a + b * c**d % e) def func(): pass On Sat, 19 Sep 2020 at 15:41, Guido van Rossum <guido@python.org> wrote:
participants (6)
-
Brandt Bucher
-
Chris Angelico
-
Christopher Barker
-
Guido van Rossum
-
Paolo Lammens
-
Paul Moore