Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does incorrect assignment to a global variable raise 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.

like image 438
max Avatar asked Nov 26 '16 19:11

max


People also ask

Why is it bad to declare global variables?

Using global variables causes very tight coupling of code. Using global variables causes namespace pollution. This may lead to unnecessarily reassigning a global value. Testing in programs using global variables can be a huge pain as it is difficult to decouple them when testing.

What is the main problem with using global variables?

Pointers to globals are even more evil. The main problem with using global variables is that they create implicit couplings among various pieces of the program (various routines might set or modify a variable, while several more routines might read it).

What are two reasons why you should not use global variables in Python?

The reason global variables are bad is that they enable functions to have hidden (non-obvious, surprising, hard to detect, hard to diagnose) side effects, leading to an increase in complexity, potentially leading to Spaghetti code.

Do global variables take precedence?

Within the body of a function, a local variable takes precedence over a global variable with the same name. If you declare a local variable or function parameter with the same name as a global variable, you effectively hide the global variable.


1 Answers

According to Python's documentation, the interpreter will first notice an assignment for a variable named a in the scope of f() (no matter the position of the assignment in the function) and then as a consequence only recognize the variable a as a local variable in this scope. This behavior effectively shadows the global variable a.

The exception is then raised "early", because the interpreter which executes the code "line by line", will encounter the print statement referencing a local variable, which is not yet bound at this point (remember, Python is looking for a local variable here).

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".

like image 190
Antoine Bolvy Avatar answered Sep 22 '22 02:09

Antoine Bolvy