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