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!