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()
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.
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.
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With