Variabili Globali in Python
Scopri come funzionano le variabili globali in Python, come modificarle con la parola chiave global, evitare gli errori UnboundLocalError e quando usare alternative.
Le variabili globali in Python sono variabili dichiarate al di fuori di qualsiasi funzione. Esistono per tutta la durata del programma e possono essere lette da qualunque punto — ma per modificarle all'interno di una funzione è necessaria la parola chiave global. Questa pagina spiega come funzionano le variabili globali, le insidie da evitare e quando è meglio ricorrere ad alternative più appropriate.
Cosa Sono le Variabili Globali?
Una variabile globale viene creata nello scope del modulo (livello superiore) — al di fuori di qualsiasi funzione o classe. Qualsiasi codice nello stesso modulo può leggerla senza alcuna dichiarazione speciale.
Python utilizza la regola LEGB per risolvere i nomi: esegue la ricerca negli scope Local → Enclosing → Global → Built-in in quest'ordine. Una variabile globale si trova al livello "G", quindi ogni funzione riesce a trovarla dopo aver esaurito i propri scope locali e circostanti. Consulta Python Scope per una spiegazione completa di tutti e quattro i livelli.
Lettura vs. Modifica delle Variabili Globali
Leggere una variabile globale (funziona sempre)
Per impostazione predefinita, una funzione può leggere qualsiasi variabile globale senza alcuna sintassi speciale:
language = "Python"
def print_language():
print(language) # reads the global
print_language() # Output: PythonLa parola chiave global — necessaria per la modifica
Se si tenta di assegnare a una variabile all'interno di una funzione, Python crea una nuova variabile locale invece di aggiornare quella globale. Per modificare la variabile globale, è necessario dichiararla con la parola chiave global:
counter = 0
def increment():
global counter # tell Python we mean the global 'counter'
counter += 1
print("Counter:", counter)
increment() # Output: Counter: 1
increment() # Output: Counter: 2
print(counter) # Output: 2Senza global counter, la riga counter += 1 genererebbe un UnboundLocalError perché Python cercherebbe di leggere una variabile locale chiamata counter prima che venisse assegnata.
L'Insidia dell'UnboundLocalError
Questo è l'errore più comune con le variabili globali. Nel momento in cui Python vede qualsiasi assegnazione a un nome all'interno di una funzione, tratta quel nome come locale per tutta la funzione — anche nelle righe precedenti all'assegnazione:
x = 10
def broken():
print(x) # ERROR — Python sees the assignment below and marks x as local
x = 20
broken()
# UnboundLocalError: local variable 'x' referenced before assignmentPer correggere il problema, aggiungere global x all'inizio della funzione se si ha davvero bisogno di modificare la variabile globale, oppure rinominare la variabile locale se si vuole una copia indipendente.
Shadowing delle Variabili
Assegnare a un nome all'interno di una funzione senza la parola chiave global crea una variabile locale che nasconde (shadowing) quella globale — la variabile globale non viene modificata:
count = 100
def show_count():
count = 5 # local variable — shadows the global 'count'
print("Inside function:", count) # 5
show_count()
print("Outside function:", count) # 100 — global is unchangedLo shadowing non è un errore, ma può creare confusione. Usare nomi distinti per rendere evidente l'intento.
global nelle Funzioni Annidate
Se si ha bisogno di accedere a una variabile globale di livello modulo da una funzione interna (annidata), si deve usare global — non nonlocal. nonlocal raggiunge solo lo scope della funzione immediatamente circostante, non il livello del modulo:
total = 0
def outer():
def inner():
global total # reaches module scope
total += 10
inner()
outer()
outer()
print("total:", total) # Output: total: 20Confronta questo con nonlocal, che modifica la variabile della funzione circostante ma lascia invariata la variabile globale a livello di modulo:
x = "global"
def outer():
x = "outer"
def inner():
nonlocal x # modifies outer()'s x, not the module-level x
x = "inner"
inner()
print("outer x after inner():", x) # inner
outer()
print("global x after outer():", x) # global — unchangedPer un approfondimento su nonlocal, consulta Python Scope.
Costanti a Livello di Modulo — Il Caso d'Uso Appropriato
L'utilizzo più legittimo delle variabili globali a livello di modulo riguarda le costanti — valori impostati una sola volta e mai modificati durante l'esecuzione. Per convenzione, si scrivono in UPPER_SNAKE_CASE:
MAX_RETRIES = 3
DEFAULT_TIMEOUT = 30
def connect(host, retries=MAX_RETRIES, timeout=DEFAULT_TIMEOUT):
print(f"Connecting to {host} with {retries} retries, timeout={timeout}s")
connect("db.example.com")
# Output: Connecting to db.example.com with 3 retries, timeout=30sLe costanti non richiedono mai la parola chiave global perché vengono solo lette, mai riassegnate.
Buone Pratiche
1. Preferire argomenti di funzione e valori di ritorno
Passare i dati tramite le firme delle funzioni rende il codice più facile da testare e da comprendere. Questa funzione pura è più semplice rispetto all'uso di un counter globale mutabile:
def increment(counter):
return counter + 1
counter = 0
counter = increment(counter)
counter = increment(counter)
print("counter:", counter) # Output: counter: 22. Riservare i globali alle vere costanti a livello di modulo
Usare le variabili globali per valori genuinamente fissi per tutta la durata del programma (MAX_CONNECTIONS, APP_VERSION, configurazione caricata una sola volta all'avvio). Evitare variabili globali mutabili che cambiano nel tempo.
3. Usare nomi descrittivi in UPPER_SNAKE_CASE per le costanti
Un nome come MAX_RETRIES è immediatamente riconoscibile come costante di modulo. Un nome come r non lo è.
4. Inizializzare prima dell'uso
Dichiarare tutte le variabili globali all'inizio del modulo, prima di qualsiasi funzione che le utilizzi. Questo previene NameError nel caso in cui una funzione venga chiamata prima che la variabile sia stata definita.
5. Prestare attenzione con i thread
Se più thread chiamano funzioni che modificano la stessa variabile globale, si genera una race condition. Proteggere lo stato mutabile condiviso con un threading.Lock, oppure riprogettare il codice per evitare lo stato condiviso. Consulta Python Variables per una panoramica più ampia dei tipi di variabile in Python.
Riepilogo
| Situazione | Cosa fare |
|---|---|
| Leggere una variabile globale dentro una funzione | Non è necessario nulla di speciale |
| Modificare una variabile globale dentro una funzione | Aggiungere global <name> all'inizio della funzione |
| Modificare la variabile di una funzione circostante | Usare nonlocal <name> |
| Condividere un valore fisso tra molte funzioni | Dichiarare una costante a livello di modulo in UPPER_SNAKE_CASE |
| Condividere stato mutabile tra funzioni | Preferire argomenti di funzione e valori di ritorno |