ProgrammazioneSviluppatore Python

Che cos'è la 'regola LEGB' in Python? Come funziona nella ricerca del nome di una variabile? Fornisci esempi di situazioni in cui una comprensione errata di questa regola porta a bug non banali.

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Regola LEGB — è la regola per la ricerca dello spazio dei nomi (scoping) in Python. L'acronimo sta per:

  • Locale — spazio dei nomi locale (all'interno di una funzione);
  • Enclosing — spazi dei nomi di tutte le funzioni annidate;
  • Global — spazio dei moduli (variabili globali);
  • Built-in — nomi incorporati di Python (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.


Domanda insidiosa.

Come cambierebbe il comportamento della funzione se dimenticassi di dichiarare nonlocal o global durante 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.


Esempi di errori reali dovuti alla mancanza di conoscenza delle sottigliezze del tema.


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.