问题
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()
回答1:
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.
回答2:
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.
回答3:
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?
回答4:
Short explanation:
a
variable is bound to the test
function. When you attempt to print it, Python throws the error because the local variable a
will be initialized later. But if you remove the a=0
, the code will execute without any problems and output 0.
Longer explanation
Python interpreter starts searching for the variable named a
from the local scope. It sees that a
is indeed declared within the function and initialized only on the fifth line. Once it's found, the lookup is over.
When it tries to process print a
(forth line) it says 'Oh boy, I need to print a variable that's not initialized yet, I'd better throw an error.'
Explanation based on function's bytecode
If you run this code:
import dis
a = 0
def test():
print a #line 4, Error : local variable 'a' referenced before assignment
a = 0 #line 5
dis.dis(test)
you'll get this output:
6 0 LOAD_FAST 0 (a)
3 PRINT_ITEM
4 PRINT_NEWLINE
7 5 LOAD_CONST 1 (0)
8 STORE_FAST 0 (a)
11 LOAD_CONST 0 (None)
14 RETURN_VALUE
Explanation on the unclear parts of the above:
- LOAD_FAST means that
a
's reference is being pushed onto the stack. - STORE_FAST means that Python assigns 0 (from LOAD_CONST) to the local variable
a
So, the problem is that LOAD_FAST goes before STORE_FAST.
来源:https://stackoverflow.com/questions/22439752/python-local-vs-global-variables