Zakresy

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

WPROWADZENIE

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