W3docs

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 global e nonlocal
  • Insidie comuni: shadowing, UnboundLocalError e 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:

LivelloSta perCosa contiene
LLocal (Locale)Nomi definiti all'interno della funzione corrente
EEnclosing (Esterno)Nomi in qualsiasi funzione esterna, per le funzioni annidate
GGlobal (Globale)Nomi definiti al livello superiore del modulo corrente
BBuilt-inNomi 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 defined

Perché 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.3975

Entrambe 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: blue

La 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())  # 3

Ogni 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: Python

Modificare 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)            # 8

Senza 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.

python— editable, runs on the server

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 callable

Elimina 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]))  # 3

Insidie 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 unchanged

Ispezionare 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())  # True

Queste 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 here

Consulta 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 chiaveEffetto
(nessuna)Legge dallo scope più vicino tramite la ricerca LEGB
global xIndica alla funzione corrente che x fa riferimento al nome a livello di modulo
nonlocal xIndica alla funzione corrente che x fa riferimento al nome nella funzione esterna più vicina

Esercitazione

Pratica
In Python, what are the four types of scopes in the order that they are checked?
In Python, what are the four types of scopes in the order that they are checked?
Was this page helpful?