Închideri
O închidere (closure) reprezintă o funcție care își amintește mediul său lexical chiar și atunci când este executată în afara domeniului său de vizibilitate.
Tehnic, o închidere include trei componente:
- Funcția exterioară, care definește un anumit domeniu de vizibilitate și în care sunt definite unele variabile și parametri - mediul lexical.
- Variabilele și parametrii (mediul lexical) care sunt definite în funcția exterioară.
- Funcția imbricată, care folosește variabilele și parametrii funcției exterioare.
Pentru a defini închideri în Python, se folosesc funcții locale:
def outer(): # funcție exterioară
n = 5 # mediu lexical - variabilă locală
def inner(): # funcție locală
nonlocal n
n += 1 # operații cu mediul lexical
print(n)
return inner
fn = outer() # fn = inner, deoarece funcția outer returnează funcția inner
# apelăm funcția internă inner
fn() # 6
fn() # 7
fn() # 8
Aici, funcția outer definește o variabilă locală n - acesta este mediul lexical pentru funcția internă:
În interiorul funcției outer, este definită funcția internă inner, care accesează mediul său lexical - variabila n, îi crește valoarea cu unul și o afișează pe consolă:
def inner(): # funcție locală
nonlocal n
n += 1 # operații cu mediul lexical
print(n)
Această funcție locală este returnată de funcția outer:
return inner
În program, apelăm funcția outer și obținem în variabila fn funcția locală inner:
fn = outer()
Variabila fn reprezintă o închidere, adică combină două lucruri: funcția și mediul în care funcția a fost creată. Și, deși am obținut funcția locală și o putem apela în afara funcției înconjurătoare în care a fost definită, ea își amintește mediul său lexical și poate să-l acceseze și să-l modifice, așa cum vedem în ieșirea consolei:
fn() # 6
fn() # 7
fn() # 8
Utilizarea parametrilor
Pe lângă variabilele exterioare, mediul lexical include și parametrii funcției înconjurătoare. Să analizăm utilizarea parametrilor:
def multiply(n):
def inner(m): return n * m
return inner
fn = multiply(5)
print(fn(5)) # 25
print(fn(6)) # 30
print(fn(7)) # 35
Aici, funcția exterioară - multiply returnează o funcție care primește un număr și returnează un număr.
Apelul funcției multiply() returnează funcția locală inner:
def inner(m): return n * m
Această funcție își amintește mediul în care a fost creată, în special valoarea parametrului n. În plus, primește și un parametru și returnează produsul parametrilor n și m.
În final, la apelul funcției multiply, este definită variabila fn, care primește funcția locală inner și mediul său lexical - valoarea parametrului n:
fn = multiply(5)
În acest caz, parametrul n este egal cu 5.
La apelul funcției locale, de exemplu, în cazul:
print(fn(6)) # 30
Numărul 6 este transmis ca parametru m funcției locale, care returnează produsul n și m, adică 5 * 6 = 30.
De asemenea, am putea scurta acest cod folosind lambda:
def multiply(n): return lambda m: n * m
fn = multiply(5)
print(fn(5)) # 25
print(fn(6)) # 30
print(fn(7)) # 35