EDIT: Looks like this is a very old \"bug\" or, actually, feature. See, e.g., this mail
I am trying to understand the Python scoping rules. More pr
First focus on the case of a closure -- a function within a function:
x = "xtop"
y = "ytop"
def func():
x = "xlocal"
y = "ylocal"
def inner():
# global y
print(x)
print(y)
y='inner y'
print(y)
inner()
Note the commented out global in inner If you run this, it replicates the UnboundLocalError you got. Why?
Run dis.dis on it:
>>> import dis
>>> dis.dis(func)
6 0 LOAD_CONST 1 ('xlocal')
3 STORE_DEREF 0 (x)
7 6 LOAD_CONST 2 ('ylocal')
9 STORE_FAST 0 (y)
8 12 LOAD_CLOSURE 0 (x)
15 BUILD_TUPLE 1
18 LOAD_CONST 3 ()
21 LOAD_CONST 4 ('func..inner')
24 MAKE_CLOSURE 0
27 STORE_FAST 1 (inner)
14 30 LOAD_FAST 1 (inner)
33 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
36 POP_TOP
37 LOAD_CONST 0 (None)
40 RETURN_VALUE
Note the different access mode of x vs y inside of func. The use of y='inner y' inside of inner has created the UnboundLocalError
Now uncomment global y inside of inner. Now you have unambiguously create y to be the top global version until resigned as y='inner y'
With global uncommented, prints:
xlocal
ytop
inner y
You can get a more sensible result with:
x = "xtop"
y = "ytop"
def func():
global y, x
print(x,y)
x = "xlocal"
y = "ylocal"
def inner():
global y
print(x,y)
y = 'inner y'
print(x,y)
inner()
Prints:
xtop ytop
xlocal ylocal
xlocal inner y
The analysis of the closure class is complicated by instance vs class variables and what / when a naked class (with no instance) is being executed.
The bottom line is the same: If you reference a name outside the local namespace and then assign to the same name locally you get a surprising result.
The 'fix' is the same: use the global keyword:
x = "xtop"
y = "ytop"
def func():
global x, y
x = "xlocal"
y = "ylocal"
class Inner:
print(x, y)
y = 'Inner_y'
print(x, y)
Prints:
xlocal ylocal
xlocal Inner_y
You can read more about Python 3 scope rules in PEP 3104