Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python local vs global variables

I understand the concept of local and global variables in Python, but I just have a question about why the error comes out the way it is in the following code. Python execute the codes line by line, so it does not know that a is a local variable until it reads line 5. Does Python go back one line and tag it as an error after it tries to execute line 5?

a=0

def test():
    print a  #line 4, Error : local variable 'a' referenced before assignment
    a=0      #line 5

test()
like image 327
Hanhan Li Avatar asked Mar 16 '14 16:03

Hanhan Li


3 Answers

Setup and Testing

To analyze your question, let's create two separate test functions that replicate your issue:

a=0

def test1():
    print(a)

test1()

prints 0. So, calling this function is not problematic, but on the next function:

def test2():
    print(a)  # Error : local variable 'a' referenced before assignment
    a=0  

test2()

We get an error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in test2
UnboundLocalError: local variable 'a' referenced before assignment

Disassembly

We can disassemble the two functions (first Python 2):

>>> import dis
>>> dis.dis(test1)
  2           0 LOAD_GLOBAL              0 (a)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       
              5 LOAD_CONST               0 (None)
              8 RETURN_VALUE        

And we see that the first function automatically loads the global a, while the second function:

>>> dis.dis(test2)
  2           0 LOAD_FAST                0 (a)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       

  3           5 LOAD_CONST               1 (0)
              8 STORE_FAST               0 (a)
             11 LOAD_CONST               0 (None)
             14 RETURN_VALUE      

seeing that a is assigned inside it, attempts to LOAD_FAST from the locals (as a matter of optimization, as functions are pre-compiled into byte-code before running.)

If we run this in Python 3, we see nearly the same effect:

>>> test2()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in test2
UnboundLocalError: local variable 'a' referenced before assignment
>>> 
>>> import dis
>>> dis.dis(test1)
  2           0 LOAD_GLOBAL              0 (print) 
              3 LOAD_GLOBAL              1 (a) 
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
              9 POP_TOP              
             10 LOAD_CONST               0 (None) 
             13 RETURN_VALUE     

>>> dis.dis() # disassembles the last stack trace
  2           0 LOAD_GLOBAL              0 (print) 
    -->       3 LOAD_FAST                0 (a) 
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
              9 POP_TOP              

  3          10 LOAD_CONST               1 (0) 
             13 STORE_FAST               0 (a) 
             16 LOAD_CONST               0 (None) 
             19 RETURN_VALUE        

We see our error is on the LOAD_FAST again.

like image 111
Russia Must Remove Putin Avatar answered Sep 28 '22 12:09

Russia Must Remove Putin


Python doesn't execute line by line in the function code you submitted. It has first to parse it as a bloc of execution. It decides if a variable is local or global depending if it is written at (function) local level. As it is the case, it decides that the variable is local, hence the error.

like image 20
Yano Avatar answered Sep 28 '22 12:09

Yano


This is because, in python, you need to tell that you are going to modify the value of a global variable. You do that as:

def test():
  global a
  print a  #line 4, Error : local variable 'a' referenced before assignment
  a=0      #line 5

With global a, you can modify variables in the function. You may want to have a look at this:

  • Python: Why is global needed only on assignment and not on reads?
like image 33
jobin Avatar answered Sep 28 '22 10:09

jobin