Why are some @expressions syntax errors?


(Albert Hopkins) #1

I have the following 3 functions:

def dec1(func):
    return func

def dec2():
    return dec1

def dec3():
    return dec2

If I apply the @ decorator syntax to a function then:

  1. @dec1 works as expected.
  2. @dec2() works as expected.
  3. @dec3()() is a SyntaxError.

Just by looking at it, 3 seems that it shouldn’t be that different than 2 (which seems not that different than 1). So why then is it a syntax error?

Of course, not using the @ syntax (e.g. foo = dec3()()(foo)) works as expected.


(Albert Hopkins) #2

For that matter this works:

dec = lambda func: func

@dec
def myfunc():
    pass

This is a SyntaxError:

@(lambda func: func)
def myfunc():
    pass

Which should be equivalent to:

def myfunc():
    pass

myfunc = (lambda func: func)(myfunc)

These are obviously useless examples, but I’m just wondering why they are not allowed.


(Jack Jansen) #3

The grammar indeed shows that after the @ you can have only a dotted name followed by an optional arglist. So it looks quite a bit like an expression but it really isn’t.

See https://docs.python.org/3/reference/grammar.html


(Nathaniel J. Smith) #4

PEP 318 cites this email as the source of the restriction: https://mail.python.org/pipermail/python-dev/2004-August/046711.html


(Albert Hopkins) #5

Thanks for the responses. Good to know. I wonder if the gut feeling payed out. It kind of would be nice if it were an expression, but I can see how that might get confusing/ugly.