sebsite

an incomplete list of non-syntax things python raises SyntaxError for

in an earlier post i briefly talked about how SyntaxError is a lie, showing some expressions which aren't prohibited by the grammar but which still raise SyntaxError when compiled. this blog post expands on that with a bunch more examples.

(see the very end for notes on what i did and didn't decide to include in this list)

the list

return/yield outside function

>>> return 67
  File "<python-input-0>", line 1
    return 67
    ^^^^^^^^^
SyntaxError: 'return' outside function
>>> yield 67
  File "<python-input-1>", line 1
    yield 67
    ^^^^^^^^
SyntaxError: 'yield' outside function

break/continue outside loop

>>> if True:
...     break
...
  File "<python-input-2>", line 2
    break
    ^^^^^
SyntaxError: 'break' outside loop
>>> def f():
...     continue
...
  File "<python-input-3>", line 2
    continue
    ^^^^^^^^
SyntaxError: 'continue' not properly in loop

await outside function

>>> await f()
  File "<python-input-4>", line 1
    await f()
    ^^^^^^^^^
SyntaxError: 'await' outside function

await outside async function

>>> def f():
...     await g()
...
  File "<python-input-5>", line 2
    await g()
    ^^^^^^^^^
SyntaxError: 'await' outside async function

async for/with outside async function

>>> async for i in []: pass
  File "<python-input-6>", line 1
    async for i in []: pass
    ^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: 'async for' outside async function
>>> def f():
...     async with 67 as x: pass
...
  File "<python-input-7>", line 2
    async with 67 as x: pass
    ^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: 'async with' outside async function

cannot assign to __debug__

>>> __debug__ = 67
  File "<python-input-8>", line 1
    __debug__ = 67
    ^^^^^^^^^
SyntaxError: cannot assign to __debug__
>>> (__debug__ := 67)
  File "<python-input-9>", line 1
    (__debug__ := 67)
     ^^^^^^^^^
SyntaxError: cannot assign to __debug__
>>> x.__debug__ = 67
  File "<python-input-10>", line 1
    x.__debug__ = 67
    ^^^^^^^^^^^
SyntaxError: cannot assign to __debug__

cannot delete __debug__

>>> del __debug__
  File "<python-input-11>", line 1
    del __debug__
	^^^^^^^^^
SyntaxError: cannot delete __debug__
>>> del x.__debug__
  File "<python-input-12>", line 1
    del x.__debug__
	^^^^^^^^^^^
SyntaxError: cannot delete __debug__

assignment expression cannot rebind comprehension iteration variable

>>> (i := 67 for i in x)
  File "<python-input-13>", line 1
    (i := 67 for i in x)
     ^
SyntaxError: assignment expression cannot rebind comprehension iteration variable 'i'

keyword argument repeated

>>> f(x=67, x=420)
  File "<python-input-14>", line 1
    f(x=67, x=420)
	    ^^^^^
SyntaxError: keyword argument repeated: x

duplicate parameter in function definition

>>> def f(x, x): pass
  File "<python-input-15>", line 1
    def f(x, x): pass
	     ^
SyntaxError: duplicate argument 'x' in function definition

duplicate type parameter

>>> type T[x, x] = int
  File "<python-input-16>", line 1
    type T[x, x] = int
	      ^
SyntaxError: duplicate type parameter 'x'

nonlocal declaration not allowed at module level

>>> nonlocal x
  File "<python-input-17>", line 1
    nonlocal x
    ^^^^^^^^^^
SyntaxError: nonlocal declaration not allowed at module level

no binding found for nonlocal

>>> def f():
...     nonlocal x
...
  File "<python-input-18>", line 2
    nonlocal x
    ^^^^^^^^^^
SyntaxError: no binding for nonlocal 'x' found

parameter name can't be global or nonlocal

>>> def f(x):
...     global x
...
  File "<python-input-19>", line 2
    global x
    ^^^^^^^^
SyntaxError: name 'x' is parameter and global
>>> def f(x):
...     nonlocal x
...
  File "<python-input-20>", line 2
    nonlocal x
    ^^^^^^^^^^
SyntaxError: name 'x' is parameter and nonlocal

name is nonlocal and global

>>> def f():
...     global x
...     nonlocal x
...
  File "<python-input-21>", line 2
    global x
    ^^^^^^^^
SyntaxError: name 'x' is nonlocal and global

name is assigned to before global/nonlocal declaration

>>> def f():
...     x = 67
...     global x
...
  File "<python-input-22>", line 3
    global x
    ^^^^^^^^
SyntaxError: name 'x' is assigned to before global declaration
>>> def f():
...     x = 67
...     nonlocal x
...
  File "<python-input-23>", line 3
    nonlocal x
    ^^^^^^^^^^
SyntaxError: name 'x' is assigned to before nonlocal declaration

annotated name can't be global/nonlocal

>>> def f():
...     global x
...     x: int = 67
...
  File "<python-input-24>", line 3
    x: int = 67
    ^^^^^^^^^^^
SyntaxError: annotated name 'x' can't be global
>>> def f(x):
...     def g():
...         nonlocal x
...         x: int = 67
...
  File "<python-input-25>", line 4
    x: int = 67
    ^^^^^^^^^^^
SyntaxError: annotated name 'x' can't be nonlocal

footnote about what i did and didn't include in this list

the line between "syntax" error and "semantic" error is kinda blurry, especially for an interpreted language like python. most of the above examples will fail during parsing, but despite this, i view them as semantic errors, because they aren't prohibited by the grammar.

even still, there's lots of examples which i omitted because i find it ambiguous whether they should be considered "syntax" errors. i've only included examples which i believe are decidedly semantic, hence why i say this list is "incomplete". but there's certainly room for endless disagreement and bikeshedding.

my background is mostly compilers, not interpreters (yes i'm aware the line there is also extremely blurry, those definitions are mostly vibes but that's fine for what i'm trying to say here). so if i'm writing a compiler, i'd check that a break statement is used inside of a loop during the type-checking phase, rather than the parsing phase. so that's a big part of why i consider break outside of a loop to be a semantic error, rather than a syntax error. but for a python interpreter, where there's no separate type checking phase before bytecode is emitted from the AST, catching this at parse-time is a perfectly reasonable thing to do, so someone else might say this is a syntax error because of that. i'm not sure it's possible to resolve the disagreement there, so i've written this post based on my own vibes. i hope this makes sense