PEP 3104 - Access to Names in Outer Scopes. The specification for the nonlocal statement.
https://realpython.com/python-namespaces-scope/
Namespaces and Scope in Python
A 'scope' defines the visibility of a name/variable within a block.
A 'namespace' is a collection of currently defined symbolic names along with information about the object that each name references. You can think of a namespace as a dictionary in which the keys are the object names and the values are the objects themselves.
There are four types of namespaces in a Python program (LEGB rule):
(1) Local
(2) Enclosing
(3) Global
(4) Builtin
def my_len(sequence): # sequence is local """Return the length of a sequence.""" length = 0 # length is local for item in sequence: # item is local length += 1 return length
X = 99 # global name def func(): # local namespace #print(X) # UnboundLocalError, X will be local X = 88 # local name print(X) # 88, reference to the local X func() # 88 print(X) # 99, X is global here
X = 99 # global name def func(): global Z # global statement (declaration) print(X) # reading global name Y = 88 # local name Z = 77 # Z is created #print(Z) # NameError, Z is not defined X = 55 # global X changed func() # 55, here the function body is executed #print(Y) # NameError, Y is not defined print(Z) # 77, Z is global
X = 99 # global name def func(): global X # global statement print(X) # OK X = 88 # global X changed func() # 99 print(X) # 88
# PEP 227 - Statically Nested Scopes x = 1 def outer(): #from math import * # SyntaxError: import * is not allowed ... import math # possible x = 2 def inner(): # nested scope print(x) inner() outer() # print 2 from nested scope, not 1 from global scope #print(math.sin(1)) # NameError: name 'math' is not defined
def make_score(score=0): for i in [1, 2, 3, 4]: def increment(step=i): #global score #NameError: name 'score' is not defined nonlocal score # if not, there is an exception (Py3) #UnboundLocalError: local variable 'score' referenced before assignment # 'score' is not local and it is not global score = score + step print(score) increment() make_score() # 1 3 6 10