Qual è l'ambito di una variabile inizializzata in un'istruzione if?


266

Sono nuovo di Python, quindi questa è probabilmente una semplice domanda di scoping. Il seguente codice in un file Python (modulo) mi confonde leggermente:

if __name__ == '__main__':
    x = 1

print x

In altre lingue in cui ho lavorato, questo codice genererebbe un'eccezione, poiché la xvariabile è locale ifall'istruzione e non dovrebbe esistere al di fuori di essa. Ma questo codice viene eseguito e stampa 1. Qualcuno può spiegare questo comportamento? Tutte le variabili create in un modulo sono globali / disponibili per l'intero modulo?


17
Un'altra stranezza di cui potresti non essere a conoscenza: se l' ifistruzione precedente non è vera (ad esempio, non lo__name__ è , ad esempio quando importi il ​​modulo invece di eseguirlo di livello superiore), allora non sarà mai stato associato e l' istruzione successiva lancerà a . '__main__'xprint xNameError: name 'x' is not defined
Santa

Risposte:


302

Le variabili Python sono associate alla funzione, alla classe o al modulo più interni in cui sono assegnati. I blocchi di controllo come ife i whileblocchi non contano, quindi una variabile assegnata all'interno di un oggetto ifè ancora nell'ambito di una funzione, classe o modulo.

(Funzioni implicite definiti da un generatore di espressione o di un elenco / set / dict comprensione fare conte, come fanno lambda espressioni. Non si può farcire un'istruzione di assegnazione in una di queste, ma i parametri lambda e forobiettivi clausola sono assegnazione implicita.)



105

Sì, sono nello stesso "ambito locale" e in realtà il codice come questo è comune in Python:

if condition:
  x = 'something'
else:
  x = 'something else'

use(x)

Si noti che xnon è dichiarato o inizializzato prima della condizione, come sarebbe in C o Java, ad esempio.

In altre parole, Python non ha ambiti a livello di blocco. Fai attenzione, tuttavia, con esempi come

if False:
    x = 3
print(x)

che solleverebbe chiaramente NameErrorun'eccezione.


42

Scope in Python segue questo ordine:

  • Cerca nell'ambito locale

  • Cerca l'ambito di tutte le funzioni allegate

  • Cerca nell'ambito globale

  • Cerca i built-in

( fonte )

Si noti che ife altri costrutti di loop / branching non sono elencati: solo le classi, le funzioni e i moduli forniscono ambito in Python, quindi qualsiasi cosa dichiarata in un ifblocco ha lo stesso ambito di qualsiasi cosa dichiarata all'esterno del blocco. Le variabili non vengono controllate al momento della compilazione, motivo per cui altre lingue generano un'eccezione. In Python, fintanto che la variabile esiste al momento richiesto, non verrà generata alcuna eccezione.


9

Come ha detto Eli, Python non richiede una dichiarazione variabile. In C diresti:

int x;
if(something)
    x = 1;
else
    x = 2;

ma nella dichiarazione di Python è implicita, quindi quando si assegna a x viene automaticamente dichiarata. È perché Python è tipizzato in modo dinamico - non funzionerebbe in un linguaggio tipicamente statico, perché a seconda del percorso utilizzato, una variabile potrebbe essere usata senza essere dichiarata. Questo verrebbe rilevato al momento della compilazione in una lingua tipizzata staticamente, ma con una lingua tipizzata in modo dinamico è consentita.

L'unico motivo per cui un linguaggio tipizzato staticamente è limitato alla necessità di dichiarare variabili al di fuori delle ifistruzioni a causa di questo problema. Abbraccia la dinamica!


9

A differenza di linguaggi come C, una variabile Python è nell'ambito di tutta la funzione (o classe o modulo) in cui appare, non solo nel "blocco" più interno. È come se tu avessi dichiarato int xall'inizio della funzione (o classe o modulo), tranne che in Python non devi dichiarare variabili.

Si noti che l'esistenza della variabile xviene verificata solo in fase di esecuzione, ovvero quando si arriva print xall'istruzione. Se __name__non uguale "__main__", allora si otterrebbe un'eccezione: NameError: name 'x' is not defined.


Le classi non creano un ambito; una variabile "locale" in una classe viene semplicemente aggiunta al dict della classe al momento della creazione.
Chepner,

3

Sì. È anche vero per forambito. Ma non funzioni ovviamente.

Nel tuo esempio: se la condizione ifnell'istruzione è falsa, xnon verrà definita però.


2

stai eseguendo questo codice dalla riga di comando quindi le ifcondizioni sono vere ed xè impostato. Confrontare:

>>> if False:
    y = 42


>>> y
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    y
NameError: name 'y' is not defined

0

E nota che poiché i tipi di Python sono controllati solo in fase di esecuzione puoi avere un codice come:

if True:
    x = 2
    y = 4
else:
    x = "One"
    y = "Two"
print(x + y)

Ma ho problemi a pensare ad altri modi in cui il codice funzionerebbe senza errori a causa di problemi di tipo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.