2012-04-28 12 views
26

Se una funzione deve modificare una variabile dichiarata nell'ambito globale, è necessario utilizzare la dichiarazione globale. Tuttavia, se la funzione ha solo bisogno di leggere una variabile globale può farlo senza l'utilizzo di una dichiarazione globale:Python: Perché Global è necessario solo per l'assegnazione e non per le letture?

X = 10 
def foo(): 
    global X 
    X = 20 # Needs global declaration 
def bar(): 
    print(X) # Does not need global 

La mia domanda riguarda la progettazione di Python: il motivo per cui è Python progettato per consentire la lettura delle variabili globali senza usando la dichiarazione globale? Cioè, perché solo l'assegnazione della forza ha un valore globale, perché non forzare la globalizzazione anche su letture? (Ciò lo renderebbe anche ed elegante.)

Nota: Vedo che non c'è alcuna ambiguità durante la lettura, ma mentre l'assegnazione non è chiara se si intende creare una nuova variabile locale o assegnarla a quella globale. Ma, spero che ci sia una ragione migliore o intenzione per questa scelta di design irregolare da parte del BDFL.

+2

Per nascondere bug sottili? – Inverse

risposta

15

Guardate questo codice:

from module import function 

def foo(x): 
    return function(x) 

Il nome function ecco un globale. Sarebbe terribilmente noioso se dovessi dire global function per far funzionare questo codice.

Prima di dire che il tuo X e il mio function sono diversi (perché uno è una variabile e l'altro è una funzione importata), ricorda che tutti i nomi in Python sono trattati allo stesso modo: quando utilizzati, il loro valore viene cercato in la gerarchia dell'ambito. Se avevi bisogno di global X allora avresti bisogno di global function. Ick.

+3

Questo però non risponde alla domanda. Puoi estendere questo argomento anche alla modifica di globals. Perché l'esplicito globale per la modifica di globals? – jterrace

+3

Perché se non si include 'global X' l'istruzione' X = 10' creerebbe un 'X' locale vincolato a' 10' piuttosto che riconciliare il globale 'X' a' 10'. –

+4

@jterrace: la domanda era "Perché è necessario globale * solo * sull'assegnazione?"no", perché è globale necessario per l'assegnazione. " –

24

Con gli ambiti nidificati, le ricerche variabili sono semplici. Si verificano in una catena che inizia con la gente del posto, attraverso la chiusura di defs, i globals dei moduli e poi i builtin. La regola è la prima partita trovata vince. Di conseguenza, non è necessaria una dichiarazione "globale" per le ricerche.

Al contrario, con le scritture è necessario specificare a quale ambito scrivere. Non c'è altrimenti modo di determinare se "x = 10" in funzione significherebbe "scrivere in uno spazio dei nomi locale" o "scrivere in uno spazio dei nomi globale".

Sommario esecutivo, con scrittura si ha una scelta di spazio dei nomi, ma con le ricerche basta la prima regola trovata. Spero che questo aiuti :-)

Modifica: Sì, è in questo modo "perché il BDFL ha detto così", ma non è insolito in altre lingue senza dichiarazioni di tipo di avere una regola primo trovato per le ricerche e solo richiede un modificatore per le scritture non locali. Quando ci pensi, queste due regole portano a codice molto pulito poiché i modificatori di ambito sono necessari solo nel caso meno comune (scritture non locali).

+2

+1 per LEGB, ho sempre trovato facile ricordare – okm

16

Perché l'esplicito è meglio che implicito.

Non c'è ambiguità quando si legge una variabile. Ottieni sempre il primo risultato quando cerchi gli ambiti dal locale fino al globale.

Quando si assegna, ci sono solo due ambiti in cui l'interprete può assumere inequivocabilmente che si sta assegnando a: locale e globale. Poiché l'assegnazione a locale è il caso più comune e l'assegnazione a Global è in realtà scoraggiata, è l'impostazione predefinita. Per assegnare a global devi farlo in modo esplicito, dicendo all'interprete che ovunque tu usi quella variabile in questo ambito, dovrebbe andare direttamente allo scope globale e sai cosa stai facendo. Su Python 3 puoi anche assegnare al più vicino ambito di chiusura con 'non locale'.

Ricordare che quando si assegna a un nome in Python, questo nuovo compito non ha nulla a che fare con quel nome precedentemente esistente assegnato a qualcos'altro. Immaginate se non ci fosse un default su local e Python cercasse tutti gli ambiti cercando di trovare una variabile con quel nome e assegnandole come fa durante la lettura. Il comportamento delle tue funzioni potrebbe cambiare in base non solo ai tuoi parametri, ma all'ambito che li circonda. La vita sarebbe miserabile

+6

Come nota a margine che non in particolare la risposta, ho programmato in Python professionalmente per 8 anni e non ho mai usato il global per nulla –

+0

Pedro: Se stai scrivendo uno script semplice la cui funzione deve modificare lo stato globale, cosa fai ? Che cosa succede se le classi sono troppo pesanti per lo script semplice? –

6

lo dici a te stesso che con la legge non c'è ambiguità e con scrive c'è. Pertanto è necessario un meccanismo per risolvere l'ambiguità con le scritture.

Un'opzione (probabilmente effettivamente utilizzata da versioni molto vecchie di Python, IIRC) è solo per dire che le scritture vanno sempre nello scope locale. Quindi non c'è bisogno di una parola chiave global e nessuna ambiguità. Ma in questo caso non è possibile scrivere su variabili globali (senza usare cose come globals() per ottenerle in modo approssimativo), quindi non sarebbe fantastico.

Un'altra opzione, utilizzata dalle lingue che dichiarano staticamente le variabili, consiste nel comunicare in anticipo all'implementazione del linguaggio per ogni ambito i nomi locali (quelli dichiarati in tale ambito) e quali nomi sono globali (nomi dichiarati in l'ambito del modulo). Ma Python non ha variabili dichiarate, quindi questa soluzione non funziona.

Un'altra opzione sarebbe quella di avere x = 3 assegnare a una variabile locale solo se non esiste già un nome in qualche ambito esterno con nome x. Sembra che farebbe la cosa giusta in modo intuitivo? Tuttavia porterebbe ad alcuni casi d'angolo seriamente cattivi. Attualmente, dove x = 3 scrive in modo statico è determinato dal parser; o non c'è lo global x nello stesso ambito ed è una scrittura locale, oppure c'è un global x ed è una scrittura globale. Ma se ciò che farà dipende dall'ambito del modulo globale, è necessario attendere fino al runtime per determinare dove va la scrittura , il che significa che può cambiare tra le chiamate di una funzione. Pensaci. Ogni volta che crei un globale in un modulo, cambieresti il ​​comportamento di tutte le funzioni nel modulo che stava usando quel nome come un nome di variabile locale. Fare qualche modulo ambito calcolo che utilizza tmp come variabile temporanea e salutare utilizzando tmp in tutte funzioni del modulo. E rabbrividisco nel pensare agli oscuri bug che riguardano l'assegnazione di un attributo su un modulo che hai importato e poi chiamare una funzione da quel modulo. Yuck.

E un'altra opzione è quella di comunicare alla implementazione del linguaggio su ogni incarico se debba essere locale o globale. Questo è ciò che Python è andato con. Dato che esiste un valore predefinito accettabile che copre quasi tutti i casi (scrivere su una variabile locale), abbiamo l'assegnazione locale come predefinito e contrassegniamo esplicitamente gli incarichi globali con global.


C'è un'ambiguità con i compiti che hanno bisogno di un meccanismo per risolverlo. global è uno di questi meccanismi. Non è l'unico possibile, ma nel contesto di Python, sembra che tutti i meccanismi alternativi siano orribili. Non so che tipo di "miglior motivo" tu stia cercando.

+0

Ben: newbie Python qui. È possibile "iniettare" una nuova variabile globale in runtime a parte e quelli già elencati nel codice sorgente nell'ambito globale? Le tue risposte sembrano indicare questo, mi piacerebbe sapere come è possibile. –

+1

@Ashwin L'ambito globale non è diverso da qualsiasi altro ambito. Non esiste una singola dichiarazione statica di ciò che contiene; Python esegue semplicemente il codice in un modulo, come risultato di quali nomi sono assegnati nell'ambito globale. Questo è esattamente lo stesso modo in cui i nomi sono definiti nell'ambito locale. Oltre a ciò, qualsiasi altro codice con un riferimento al modulo (dopo averlo importato) può assegnare degli attributi su di esso, e gli attributi del modulo sono solo le variabili globali all'interno di quel modulo. Le funzioni più nel modulo potrebbero usare 'global'. È questo il genere di cose a cui ti stai riferendo? – Ben

+0

Ben: capito. Grazie :-) –

Problemi correlati