Extending the usage of the @ decoration operator.

Right now, one can use the @ symbol only for decorations and only bofore function or class definition. ("A decorator is just a callable that takes a function as an argument and returns a replacement function."). @dec1(arg) @dec2 def func(): pass If a function has already been defined, it cannot be decorated using the decoration operator. But it can still be decorated by explicitly calling the decorator: @dec1(arg) @dec2 def func(): pass is equivalent to: def func(): pass func = dec1(arg)(dec2(func)) Now I propose that the @ symbol should also be usable as an assignment operator, in which case a succeeding function definition would not be decorated: def foo(): pass foo @ decorator def bar(): pass is equivalent to: def foo(): pass foo = decorator(func) def bar(): pass This doesn't allow us to have stacked decorators so, the use of a tuple is needed: def func(): pass func @ (dec2, dec1(arg)) is equivalent to: def func(): pass func = dec1(arg)(dec2(func)) Why not decorate more than one function at once?: func1, func2, func3 @ dec1(arg), dec2 is equivalent to: func1 = dec1(arg)(dec2(func1)) func2 = dec1(arg)(dec2(func2)) func3 = dec1(arg)(dec2(func3)) or better: _temp1 = dec1(arg)(dec2(func1)) _temp2 = dec1(arg)(dec2(func2)) _temp3 = dec1(arg)(dec2(func3)) func1, func2, func3 = _temp1, _temp2, _temp3 The @ operator would still be only used for function decoration. But it should pass any object preceding it as the (only) argument to the first callable - let's call them modifiers - in the tuple succeeding it and then pass the return value to the next modifier in the tuple. The last return value should then be assigned to the variable again. Consider the following example: from os.path import expandvars, abspath, normcase p1 = input('Insert path here: ) p2 = input('And another path here: ) # Fix the path strings p1, p2 @ expandvars, abspath, normcase Functions that take more than one argument can't be used as modifiers. But simply currying them solves the problem: from os.path import expandvars, abspath, normcase, relpath def curry(f, *args, **kwargs): def curried_f(arg1): return f(arg1, *args, **kwargs) return curried_f # Fix the path strings p1, p2 @ expandvars, abspath, normcase, curry(relpath, start) Storing the modifiers in a mutable like a list, one could do rather complex stuff: def add(a, b): return a + b def sub(...; def mult(...; def div(... # ...the obvious way. def permutations(L): for _ in range(possible_permutations) next_permutation = ... yield next_permutation L = [curry(add, 1), curry(sub, 2), curry(mult, 3), curry(div, 4)] # Prints the result for all possible combinations of the four operations +1, -2, *3, /4 # applied to 1. for permutation in permutations(L): x = 1 x @ permutation print(x) I'm not sure where to go from here. Does this idea qualify for a PEP? Is it even possible to be implemented? Has it already been discussed? What do you think about it? Please share your opinions, suggestions and improvements!

On 2014-05-17 02:40, Chris B wrote:
Right now, one can use the @ symbol only for decorations and only bofore function or class definition. ("A decorator is just a callable that takes a function as an argument and returns a replacement function.").
@dec1(arg) @dec2 def func(): pass
If a function has already been defined, it cannot be decorated using the decoration operator. But it can still be decorated by explicitly calling the decorator:
@dec1(arg) @dec2 def func(): pass
is equivalent to:
def func(): pass func = dec1(arg)(dec2(func))
Now I propose that the @ symbol should also be usable as an assignment operator, in which case a succeeding function definition would not be decorated:
[snip] There is a proposal to use @ as an operator for matrix multiplication: http://legacy.python.org/dev/peps/pep-0465/

On 05/16/2014 07:08 PM, MRAB wrote:
On 2014-05-17 02:40, Chris B wrote:
Right now, one can use the @ symbol only for decorations and only bofore function or class definition. ("A decorator is just a callable that takes a function as an argument and returns a replacement function.").
@dec1(arg) @dec2 def func(): pass
If a function has already been defined, it cannot be decorated using the decoration operator. But it can still be decorated by explicitly calling the decorator:
@dec1(arg) @dec2 def func(): pass
is equivalent to:
def func(): pass func = dec1(arg)(dec2(func))
Now I propose that the @ symbol should also be usable as an assignment operator, in which case a succeeding function definition would not be decorated:
[snip] There is a proposal to use @ as an operator for matrix multiplication:
Which has been accepted. -- ~Ethan~

On Sat, May 17, 2014 at 03:08:31AM +0100, MRAB wrote:
On 2014-05-17 02:40, Chris B wrote:
Right now, one can use the @ symbol only for decorations and only bofore function or class definition. ("A decorator is just a callable that takes a function as an argument and returns a replacement function."). [...] There is a proposal to use @ as an operator for matrix multiplication:
It's not just a proposal, it's accepted and implemented in Python 3.5: http://bugs.python.org/issue21176 So regardless of the merits of this proposal (if any), it isn't going to happen. -- Steven

On 17 May 2014 11:40, Chris B <accountearnstar@gmail.com> wrote:
I'm not sure where to go from here. Does this idea qualify for a PEP? Is it even possible to be implemented? Has it already been discussed? What do you think about it? Please share your opinions, suggestions and improvements!
Others have noted that this specific proposal conflicts with the already accepted matrix multiplication operator, but there are some more general questions to ask yourself when making syntax proposals: * what problem am I trying to solve? * how common is that problem in general? * what are the existing solutions to that problem? * how easy is it to make a mistake when relying on the existing solutions? * how does the readability of the new syntax compare to existing code? * how much harder will it be to learn Python after this proposal is added? For example, the original decorator syntax solved a significant readability problem: def method(a, b, c): # Where is self???? # many # lines # of # implementation method = staticmethod(method) # Oh, it's a static method vs @staticmethod def method(a, b, c): # Obviously no self needed # many # lines # of # implementation By contrast, a new way of spelling the "method = staticmethod(method)" line isn't particularly interesting - it doesn't add much expressiveness to the language, just a new way of spelling something that can already be written out explicitly. Adding a complicated way of avoiding writing multiple assignment statements or a helper function also isn't compelling: p1, p2 @ expandvars, abspath, normcase, curry(relpath, start) vs def fixpath(p): return expandvars(abspath(normcase(relpath(start, p)))) p1 = fixpath(input('Insert path here: ')) p2 = fixpath(input('And another path here: ')) Python aspires to be "executable pseudocode". While we often fall short of that mark, it does at least mean we're willing to sacrifice a little brevity for the sake of clarity. For a more recent example of a successful syntax change proposal, the numeric Python community were able to make their case for a new matrix multiplication operator because they have been trying to solve it *without* a new operator for more than a decade, but haven't been able to come up with a non-syntactic solution that they were all happy with. The PEP was accepted in short order because they were able to demonstrate two things: 1. Yes, they really needed new syntax to solve the problem properly 2. No, they weren't likely to be back in a couple of years time asking for *another* operator in 3.6 - matrix multiplication really was the only thing they had found they didn't have a good clean spelling for http://www.curiousefficiency.org/posts/2011/02/justifying-python-language-ch... has a few more examples of past changes that were accepted, and some of the key reasons why. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
participants (5)
-
Chris B
-
Ethan Furman
-
MRAB
-
Nick Coghlan
-
Steven D'Aprano