Where a name lives, where Python looks for it, and how global and nonlocal change that.
Inside inner(), a name is searched for from the inside out:
# global variable
x = 10
def func():
print(x)
func()
# ans: 10
A function can read a global name: it isn't local, so the search moves outwards.
# local variable
def func():
y = 20
print(y)
func()
# ans: 20
print(y)
# ans: NameError: name 'y' is not defined
A local variable lives in the call's frame and is gone once the call returns.
# modify global variable
count = 0
def increment():
global count
count += 1
increment()
# ans: count is 1
global count makes assignments inside the function change the global frame's count.
# modify enclosing scope
def outer():
x = 10
def inner():
nonlocal x
x = 20
inner()
return x
result = outer()
# ans: 20
nonlocal reaches one level out, to the enclosing function's frame.
# local shadows global
x = 10
def func():
x = 5
print(x)
func()
# ans: 5
print(x)
# ans: 10
Assigning inside a function creates a new local x; the global x is untouched.
Predict the result, then press → to run the code and check.
# what is printed?
x = 5
def func():
print(x)
func()
# ans: 5
# what happens?
x = 5
def func():
x = 10
func()
print(x)
# ans: 5 (the local x doesn't affect the global)
# global keyword?
x = 5
def func():
global x
x = 10
func()
print(x)
# ans: 10
# can you do this?
def func():
print(x)
x = 5
func()
# ans: UnboundLocalError
Python decides a name is local for the whole function if it is assigned anywhere in it.
# nonlocal?
def outer():
x = 5
def inner():
nonlocal x
x = 10
inner()
return x
outer()
# ans: 10
# nested functions?
def outer():
x = 5
def inner():
return x
return inner()
outer()
# ans: 5
# what is x?
x = 1
def func():
x = x + 1
func()
# ans: UnboundLocalError
The assignment makes x local, so x + 1 reads a local that has no value yet.
# parameter scope?
def func(x):
x = 10
x = 5
func(x)
print(x)
# ans: 5
# global in nested?
x = 5
def outer():
def inner():
global x
x = 10
inner()
outer()
print(x)
# ans: 10
# closure?
def outer(x):
def inner(y):
return x + y
return inner
f = outer(10)
f(5)
# ans: 15
A closure: inner keeps x alive after outer has returned.
Names are looked up Local, Enclosing, Global, then Built-in.
Assigning a name anywhere in a function makes it local there, unless declared otherwise.
global / nonlocalLet a function change a module-level name, or one in the enclosing function.
An inner function remembers the enclosing variables it uses.