Scope in Python
Impara lo scope in Python e la regola LEGB: scope locale, esterno, globale e built-in con esempi chiari, errori comuni e le parole chiave global/nonlocal.
Comprendere lo scope in Python
Lo scope determina dove un nome di variabile è visibile e per quanto tempo esiste. Ogni nome che crei — una variabile, una funzione, una classe — appartiene esattamente a uno scope. Quando Python incontra un nome, cerca negli scope in un ordine preciso finché non trova il nome o genera un NameError.
Questa pagina tratta:
- I quattro livelli di scope e la regola di ricerca LEGB
- Le parole chiave
globalenonlocal - Insidie comuni: shadowing,
UnboundLocalErrore fuga dei nomi - Come ispezionare gli scope in fase di esecuzione
La regola LEGB
Python risolve i nomi in quattro livelli, cercando dall'interno verso l'esterno:
| Livello | Sta per | Cosa contiene |
|---|---|---|
| L | Local (Locale) | Nomi definiti all'interno della funzione corrente |
| E | Enclosing (Esterno) | Nomi in qualsiasi funzione esterna, per le funzioni annidate |
| G | Global (Globale) | Nomi definiti al livello superiore del modulo corrente |
| B | Built-in | Nomi precaricati da Python — print, len, range, type, ecc. |
Python si ferma alla prima corrispondenza. Se non viene trovata alcuna corrispondenza in nessun livello, viene generato un NameError.
Scope locale
Un nome è locale quando viene assegnato all'interno di una funzione. Viene creato quando la funzione è chiamata e distrutto quando la funzione ritorna. I nomi locali non sono visibili all'esterno della funzione.
def greet():
message = "Hello, World!" # local variable
print(message) # accessible here
greet()
# Output: Hello, World!
print(message) # NameError: name 'message' is not definedPerché lo scope locale è importante
Lo scope locale ti permette di usare nomi semplici e descrittivi come total, result o i all'interno di ogni funzione senza che nessuno di essi entri in conflitto con gli altri o con il codice a livello di modulo.
def calculate_area(radius):
pi = 3.14159 # local to this function
area = pi * radius ** 2
return area
def calculate_volume(radius, height):
pi = 3.14159 # completely separate local 'pi'
volume = pi * radius ** 2 * height
return volume
print(calculate_area(5)) # 78.53975
print(calculate_volume(5, 10)) # 785.3975Entrambe le funzioni usano pi in modo indipendente. Non vi è alcun conflitto.
Scope esterno (Enclosing)
Quando una funzione è definita all'interno di un'altra funzione, la funzione interna può leggere i nomi dalla funzione esterna (enclosing). Questa è la E in LEGB.
def outer():
color = "blue" # enclosing variable
def inner():
print(color) # reads from enclosing scope
inner()
outer()
# Output: blueLa funzione interna può leggere color senza alcuna parola chiave speciale perché Python risale automaticamente allo scope esterno.
Modificare una variabile esterna con nonlocal
Leggere una variabile esterna è automatico, ma per assegnarle un valore è necessaria la parola chiave nonlocal. Senza di essa, Python tratta l'assegnazione come la creazione di una nuova variabile locale, non come la modifica di quella esterna.
def make_counter():
count = 0 # enclosing variable
def increment():
nonlocal count # declare intent to modify the enclosing 'count'
count += 1
return count
return increment
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3Ogni chiamata a counter() modifica la stessa variabile count. Questo schema è la base delle closure — consulta Python Closures per un approfondimento.
Scope globale
I nomi definiti al livello superiore di un modulo (al di fuori di qualsiasi funzione) sono globali. Sono accessibili da qualsiasi punto dello stesso modulo, anche all'interno delle funzioni.
language = "Python" # global variable
def display_language():
print(language) # reads global without any keyword
display_language()
# Output: PythonModificare una variabile globale con global
Puoi leggere una variabile globale dall'interno di una funzione senza alcuna parola chiave. Ma se vuoi assegnarle un valore, devi prima dichiararla con global:
total = 0 # global variable
def add_to_total(n):
global total # declare intent to modify the global
total += n
add_to_total(5)
add_to_total(3)
print(total) # 8Senza global total, la riga total += n genererebbe un UnboundLocalError perché Python tratterebbe total come una variabile locale non ancora assegnata.
Per ulteriori informazioni sulle variabili globali consulta Python Global Variables.
Quando evitare global
Usare global estensivamente rende il codice più difficile da testare e da comprendere. Preferisci restituire valori dalle funzioni e passare i dati come argomenti. Riserva global per un autentico stato a livello di modulo — flag di configurazione, contatori o cache — e usalo raramente.
Scope built-in
Lo scope built-in contiene i nomi che Python fornisce automaticamente. Sono disponibili in ogni modulo senza alcuna importazione.
I nomi built-in comuni includono print, len, range, type, int, str, list, dict, set, tuple, open, input, max, min, sum, sorted, enumerate, zip e map.
Non oscurare i nomi built-in
Poiché lo scope built-in viene cercato per ultimo, qualsiasi nome locale o globale con la stessa ortografia lo oscurerà. Questo è un errore comune:
# Bad: shadows the built-in 'list'
list = [1, 2, 3]
print(type(list)) # <class 'list'> — still works here
new = list([4, 5]) # TypeError: 'list' object is not callableElimina il nome che fa shadowing per ripristinare il built-in:
del list # remove the local/global shadowing name
new = list([4, 5]) # works again: [4, 5]Il modulo built-in è disponibile come builtins se hai mai bisogno di accedervi esplicitamente:
import builtins
print(builtins.len([1, 2, 3])) # 3Insidie comuni
UnboundLocalError
L'errore di scope più frequente in Python si verifica quando si legge un nome prima di assegnarlo all'interno di una funzione in cui è presente anche un'assegnazione a quel nome in qualsiasi punto della stessa funzione:
x = 10
def bad_func():
print(x) # UnboundLocalError! Python sees x = 20 below
x = 20 # this makes 'x' local for the whole function
bad_func()Python decide al momento della compilazione che x è locale (perché viene assegnato nella funzione). Il tentativo di leggerlo prima dell'assegnazione genera UnboundLocalError: local variable 'x' referenced before assignment.
Correggilo dichiarando global x oppure non assegnando nulla a x all'interno della funzione.
Shadowing delle variabili
Una variabile locale che condivide il nome con una globale oscura silenziosamente quest'ultima. Di solito è intenzionale, ma può causare bug subdoli quando ci si aspetta di leggere la variabile globale:
x = 10 # global
def my_func():
x = 20 # local — shadows the global
print(x) # 20, not 10
my_func()
print(x) # 10 — global unchangedIspezionare lo scope in fase di esecuzione
Python espone il contenuto dello scope corrente attraverso due funzioni built-in.
locals() restituisce un dizionario dello scope locale corrente (o il namespace a livello di modulo se chiamata al livello superiore):
def show_locals():
a = 1
b = "hello"
print(locals()) # {'a': 1, 'b': 'hello'}
show_locals()globals() restituisce il dizionario del namespace globale (a livello di modulo):
language = "Python"
print("language" in globals()) # TrueQueste funzioni sono utili per il debug e l'introspezione, ma non devono essere usate per manipolare variabili dinamicamente nel codice in produzione.
Scope e funzioni
Le funzioni in Python sono oggetti e sono esse stesse nomi che vivono in qualche scope. Una funzione definita all'inizio di un modulo è globale; una funzione definita all'interno di un'altra funzione è locale alla funzione esterna.
def outer():
def helper(): # helper is local to outer
return 42
return helper()
print(outer()) # 42
# helper() # NameError: helper is not defined hereConsulta Python Functions per come si definiscono le funzioni, e Python Lambda per le funzioni anonime che seguono anch'esse la regola LEGB.
Riferimento rapido
| Parola chiave | Effetto |
|---|---|
| (nessuna) | Legge dallo scope più vicino tramite la ricerca LEGB |
global x | Indica alla funzione corrente che x fa riferimento al nome a livello di modulo |
nonlocal x | Indica alla funzione corrente che x fa riferimento al nome nella funzione esterna più vicina |