In the Resolution of Names section of the Python Reference Manual this is stated:
[..] If the current scope is a function scope, and the name refers to a local variable that has not yet been bound to a value at the point where the name is used, an UnboundLocalError
exception is raised [..]
that's the official word on when UnboundLocalError
occurs. If you take a look at the bytecode CPython generates for your function f
with dis
you can see it trying to load the name from a local scope when its value hasn't even been set yet:
>>> dis.dis(f)
3 0 LOAD_GLOBAL 0 (print)
3 LOAD_CONST 1 (1)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
4 10 LOAD_GLOBAL 0 (print)
13 LOAD_FAST 0 (a) # <-- this command
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
19 POP_TOP
5 20 LOAD_CONST 2 (20)
23 STORE_FAST 0 (a)
26 LOAD_CONST 0 (None)
29 RETURN_VALUE
As you can see, the name 'a'
is loaded onto the stack by means of the LOAD_FAST
command:
13 LOAD_FAST 0 (a)
This is the command that is used to grab local variables in a function (named FAST
due to it being quite faster than loading from the global scope with LOAD_GLOBAL
).
This really has nothing to do with the global name a
that has been defined previously. It has to do with the fact that CPython will assume you're playing nice and generate a LOAD_FAST
for references to 'a'
since 'a'
is being assigned to (i.e made a local name) inside the function body.
For a function with a single name access and no corresponding assignment, CPython does not generate a LOAD_FAST
and instead goes and looks at the global scope with LOAD_GLOBAL
:
>>> def g():
... print(b)
>>> dis.dis(g)
2 0 LOAD_GLOBAL 0 (print)
3 LOAD_GLOBAL 1 (b)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
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)?
In the Compound Statements section of the reference manual the following is stated for function definitions:
A function definition is an executable statement. Its execution binds the function name in the current local namespace to a function object (a wrapper around the executable code for the function).
Specifically, it binds the name f
to a function object that holds the compiled code, f.__code__
, that dis
prettifies for us.
access*write to* global variables from inside functions by default. You will have to explicitly declare that you mean to use a global. (btw Don't Use Global Variables). – quamrana Nov 26 '16 at 19:29