Regola LEGB — è la regola per la ricerca dello spazio dei nomi (scoping) in Python. L'acronimo sta per:
len, list, ecc.).Quando Python incontra una variabile, cerca prima localmente, poi nelle funzioni annidate, quindi nell'area globale del modulo, e infine nello spazio dei nomi degli oggetti incorporati:
def outer(): x = 'enclosing' def inner(): x = 'local' print(x) inner() outer() # 'local'
Se dentro inner() si rimuove l'assegnazione a x, Python prenderà x dallo scopo enclosing (outer). Se non c'è neanche lì — cerca globalmente, poi negli incorporati.
Come cambierebbe il comportamento della funzione se dimenticassi di dichiarare
nonlocaloglobaldurante la modifica di una variabile di un livello superiore?
Risposta:
Se si prova a modificare una variabile di uno scopo esterno all'interno di una funzione annidata senza dichiarare nonlocal (o global — se la variabile è nel modulo), Python creerà una nuova variabile locale, senza modificare quella esterna.
Esempio:
x = 10 def foo(): x = 20 # Questa è una nuova x locale, la globale non viene modificata foo() print(x) # 10
Per modificare la x globale:
def foo(): global x x = 20
Con le variabili nella funzione esterna — usa nonlocal.
Storia 1
In un progetto educativo sono state utilizzate funzioni annidate per contare il numero di chiamate. Lo sviluppatore ha scritto:
def counter(): count = 0 def inc(): count += 1 return count return inc
Ma si è verificato UnboundLocalError, perché count dentro inc() è stato considerato nuovo (è stata creata una count locale). Soluzione: dichiarare count come nonlocal.
Storia 2
In un'app web si voleva modificare globalmente la cache definita:
cache = {} def add_to_cache(key, value): cache[key] = value
Tuttavia, se all'interno della funzione si fosse tentato di riscrivere completamente cache, ad esempio cache = {key: value}, questo avrebbe creato una nuova cache locale, non collegata all'originale, a causa della mancanza di global cache.
Storia 3
In un grande sistema ETL è stato riscontrato un bug: i programmatori hanno lasciato la variabile result senza una chiara inizializzazione all'interno della funzione, aspettandosi che fosse presa dallo scopo esterno. Ma dopo alcune iterazioni il risultato ha cominciato a essere errato, poiché all'interno c'era la scrittura result += value, e non result = result + value (senza nonlocal/global) — e result veniva inizializzata di nuovo a ogni chiamata.