max max - 13 days ago 13
Python Question

Why does incorrect assignment to a global variable raises exception early?

a = 10
def f():
print(1)
print(a) # UnboundLocalError raised here
a = 20
f()


This code of course raises
UnboundLocalError: local variable 'a' referenced before assignment
. But why is this exception raised at the
print(a)
line?

If the interpreter executed code line by line (like I thought it did), it wouldn't know anything was wrong when
print(a)
was reached; it would just think that
a
referred to the global variable.

So it appears the interpreter reads the entire function in advance to figure out whether
a
is used for assignment. Is this documented anywhere? Is there any other occasion where the interpreter looks ahead (apart from checking for syntax errors)?

To clarify, the exception itself is perfectly clear: global variables can be read without
global
declaration, but not written (this design prevents bugs due to unintentionally modifying global variables; those bugs are especially hard to debug because they lead to errors that occur far from the location of the erroneous code). I'm just curious why the exception is raised early.

Answer

This is because according to Python's documentation, the interpreter will notice an assignment for the global variable in the scope, then from this point recognize the variable a as a local variable, therefore shadowing the global a variable.

The exception is then raised "early", because the interpreter, still executing the code "line by line", will encounter the print statement referencing a local variable, which is not yet bound.

As you mentioned in your question, one has to use the global keyword to explicitly tell the compiler that the assignment in this scope is done to the global variable the correct code would be:

a = 10
def f():
  global a
  print(1)
  print(a) # Prints 10 as expected
  a = 20
f()

As @2rs2ts said in a now-deleted answer, this is easily explained by the fact that "Python is not merely interpreted, it is compiled into a bytecode and not just interpreted line by line".