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
Każda zmienna żyje w określonej przestrzeni nazw (namespace). Kiedy mówimy o szukaniu wartości nazwy w odniesieniu do kodu, do przestrzeni nazw odnosi się zakres (scope). Funkcje definiują zakres lokalny, a moduły zakres globalny. Rozwiązywanie konfliktów w zakresie nazw w Pythonie nazywane jest regułą LEGB (local, enclosing, global, builtin).
Python wykorzystuje lokalizację przypisania do nazwy do powiązania jej z określoną przestrzenią nazw.
Należy unikać stosowania zmienych globalnych w funkcjach, ponieważ programy stają się trudniejsze do debugowania. Ponadto przy czytaniu kodu programu można zostać łatwo wprowadzonym w błąd.
X = 99 # zmienna globalna (automatycznie)
def func():
#print(X) # NameError, X będzie lokalne
X = 88 # zmienna lokalna
print(X) # odwołanie do lokalnego X
func() # 88, lokalne X
print(X) # 99, globalne X
X = 99 # zmienna globalna
def func():
global Z # deklaracja przypisania zmiennej globalnej
print(X) # odwołanie do zmiennej globalnej (odczyt)
Y = 88 # zmienna lokalna
Z = 77
X = 55 # zmiana zmiennej globalnej X
func() # 55, rozwiązywanie nazw następuje w czasie wykonania!
#print(Y) # NameError, Y nie istnieje
print(Z) # 77, Z jest globalne
X = 99 # zmienna globalna
def func():
global X # deklaracja przestrzeni nazw
print(X) # dozwolone
X = 88 # zmiana zmiennej globalnej
func() # 99, stara wartość zmiennej globalnej
print(X) # 88, nowa wartość zmiennej globalnej
# https://www.python.org/dev/peps/pep-0227/
# PEP 227 - Statically Nested Scopes
# Przykład działania nested scopes, zagnieżdżonych zakresów.
x = 1
def outer():
#from math import * # SyntaxError: import * is not allowed ...
import math # dozwolone
x = 2
def inner():
print(x)
inner()
outer() # wypisze 2 z zagnieżdżonego zakresu
#print(math.sin(1)) # NameError: name 'math' is not defined
# Funkcja inner() widzi zmienną x z zakresu zagnieżdżonego wewnątrz
# funkcji outer(), a nie z zakresu globalnego, jak było w Py2.1.
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 # Py3, bez tego komunikat
#UnboundLocalError: local variable 'score' referenced before assignment
# Wskazujemy, że score nie jest lokalna wewnątrz increment(),
# nie jest globalna, jest w zakresie make_score().
score = score + step
print(score)
increment()
make_score() # 1 3 6 10