Non c'è stata una risposta completa riguardo al tempo di Python3, quindi ho fatto una risposta qui. Gran parte di ciò che è descritto qui è dettagliato nella Risoluzione 4.2.2 dei nomi della documentazione di Python 3.
Come indicato in altre risposte, ci sono 4 ambiti di base, il LEGB, per Local, Enclosing, Global e Builtin. Oltre a questi, esiste un ambito speciale, il corpo della classe , che non comprende un ambito di applicazione per i metodi definiti all'interno della classe; qualsiasi assegnazione all'interno del corpo della classe rende la variabile da lì in poi vincolata nel corpo della classe.
Soprattutto, nessuna istruzione di blocco, a parte def
eclass
, creare un ambito variabile. In Python 2 la comprensione di una lista non crea un ambito variabile, tuttavia in Python 3 la variabile di ciclo all'interno della comprensione di un elenco viene creata in un nuovo ambito.
Per dimostrare le peculiarità del corpo di classe
x = 0
class X(object):
y = x
x = x + 1 # x is now a variable
z = x
def method(self):
print(self.x) # -> 1
print(x) # -> 0, the global x
print(y) # -> NameError: global name 'y' is not defined
inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)
Pertanto, diversamente dal corpo della funzione, è possibile riassegnare la variabile allo stesso nome nel corpo della classe, per ottenere una variabile di classe con lo stesso nome; ulteriori ricerche su questo nome vengono invece risolte nella variabile di classe.
Una delle maggiori sorprese per molti nuovi arrivati su Python è che un for
loop non crea un ambito variabile. In Python 2 la comprensione dell'elenco non crea neanche un ambito (mentre lo fanno i generatori e le comprensioni dict!) Invece perdono il valore nella funzione o nell'ambito globale:
>>> [ i for i in range(5) ]
>>> i
4
Le comprensioni possono essere usate come un modo astuto (o terribile se vuoi) per creare variabili modificabili all'interno delle espressioni lambda in Python 2 - un'espressione lambda crea un ambito variabile, come il def
farebbe affermazione, ma all'interno di lambda non sono consentite istruzioni. L'assegnazione essendo un'istruzione in Python significa che non sono consentite assegnazioni variabili in lambda, ma la comprensione di un elenco è un'espressione ...
Questo comportamento è stato corretto in Python 3: nessuna espressione di comprensione o variabili di perdita dei generatori.
Il globale significa davvero l'ambito del modulo; il modulo principale di Python è il __main__
; tutti i moduli importati sono accessibili tramite la sys.modules
variabile; per ottenere l'accesso __main__
si può usare sys.modules['__main__']
, oppure import __main__
; è perfettamente accettabile accedere e assegnare attributi lì; verranno visualizzati come variabili nell'ambito globale del modulo principale.
Se viene mai assegnato un nome nell'ambito corrente (tranne nell'ambito della classe), verrà considerato appartenente a tale ambito, altrimenti verrà considerato come appartenente a qualsiasi ambito racchiuso che assegna alla variabile (potrebbe non essere assegnato ancora, o per niente), o infine l'ambito globale. Se la variabile è considerata locale, ma non è stata ancora impostata o è stata eliminata, si otterrà la lettura del valore della variabile UnboundLocalError
, che è una sottoclasse di NameError
.
x = 5
def foobar():
print(x) # causes UnboundLocalError!
x += 1 # because assignment here makes x a local variable within the function
# call the function
foobar()
L'ambito può dichiarare che desidera esplicitamente modificare la variabile globale (ambito del modulo), con la parola chiave globale:
x = 5
def foobar():
global x
print(x)
x += 1
foobar() # -> 5
print(x) # -> 6
Anche questo è possibile anche se è stato ombreggiato nell'ambito compreso:
x = 5
y = 13
def make_closure():
x = 42
y = 911
def func():
global x # sees the global value
print(x, y)
x += 1
return func
func = make_closure()
func() # -> 5 911
print(x, y) # -> 6 13
In python 2 non esiste un modo semplice per modificare il valore nell'ambito compreso; di solito questo viene simulato con un valore modificabile, come un elenco con lunghezza 1:
def make_closure():
value = [0]
def get_next_value():
value[0] += 1
return value[0]
return get_next_value
get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2
Tuttavia in Python 3, nonlocal
viene in soccorso:
def make_closure():
value = 0
def get_next_value():
nonlocal value
value += 1
return value
return get_next_value
get_next = make_closure() # identical behavior to the previous example.
La nonlocal
documentazione dice che
I nomi elencati in un'istruzione non locale, a differenza di quelli elencati in un'istruzione globale, devono fare riferimento a associazioni preesistenti in un ambito di chiusura (l'ambito in cui creare una nuova associazione non può essere determinato in modo univoco).
ie nonlocal
si riferisce sempre all'ambito non globale esterno più interno a cui è stato associato il nome (ovvero assegnato a, incluso usato come for
variabile target, nella with
clausola o come parametro di funzione).
Qualsiasi variabile che non è considerata locale per l'ambito corrente, o qualsiasi ambito incluso, è una variabile globale. Un nome globale viene cercato nel dizionario globale del modulo; se non trovato, il globale viene quindi cercato dal modulo incorporato; il nome del modulo è stato cambiato da python 2 a python 3; in Python 2 lo era __builtin__
e in Python 3 è ora chiamato builtins
. Se si assegna a un attributo del modulo incorporato, sarà successivamente visibile a qualsiasi modulo come variabile globale leggibile, a meno che quel modulo non li ombreggi con la propria variabile globale con lo stesso nome.
La lettura del modulo integrato può anche essere utile; supponiamo che tu voglia la funzione di stampa in stile python 3 in alcune parti del file, ma altre parti del file usano ancora l' print
istruzione. In Python 2.6-2.7 puoi ottenere la print
funzione Python 3 con:
import __builtin__
print3 = __builtin__.__dict__['print']
In from __future__ import print_function
realtà, la print
funzione non importa da nessuna parte in Python 2, ma disabilita semplicemente le regole di analisi per l' print
istruzione nel modulo corrente, gestendola print
come qualsiasi altro identificatore di variabile e consentendo così la ricerca print
della funzione nei builtin.