2012-10-02 13 views
52

Qual è la ragione di avere la funzione globals() in Python? Restituisce solo il dizionario delle variabili globali, che sono già globali, in modo che possano essere utilizzate ovunque ... Chiedo solo per curiosità, cercando di imparare Python.Motivo per globals() in Python?

def F(): 
    global x 
    x = 1 

def G(): 
    print(globals()["x"]) #will return value of global 'x', which is 1 

def H(): 
    print(x) #will also return value of global 'x', which, also, is 1 

F() 
G() 
H() 

Non riesco davvero a vedere il punto qui? Solo il tempo avrei bisogno, era se avessi variabili locali e globali, con lo stesso nome per entrambi

def F(): 
    global x 
    x = 1 

def G(): 
    x = 5 
    print(x) #5 
    print(globals()["x"]) #1 

F() 
G() 

Ma non si dovrebbe mai incorrere in un problema di avere due variabili con lo stesso nome, e che hanno bisogno di usare entrambi nello stesso ambito.

+2

"Ma non si dovrebbe mai incontrare il problema di avere due variabili con lo stesso nome e di usarle entrambe nello stesso ambito." Non posso seguire questo pensiero. Questa è l'intera ragione per spazi dei nomi separati, che hai variabili con lo stesso nome in ambiti diversi. Quando lavori con due di essi, i nomi duplicati sono una cosa naturale, ma non un problema, dato che puoi prefissarli. – Michael

+0

Bene, vengo dalla famiglia C++, quindi non sono sicuro delle persone Python, ma per quanto posso pensare, non dovresti avere una variabile ** globale ** che non ha un nome univoco. Certo ci saranno variabili con lo stesso nome, nello stesso ambito, che è stata una mia stupida frase, ma non globali con lo stesso nome di quelli locali. Ecco quando userei spazi dei nomi per quelli locali ... Ma non so, se lo dici tu. –

+3

@Mahi: 'globals' è forse un po 'fuorviante. 'globals()' è essenzialmente il 'locals()' di un modulo.Il Python più vicino arriva a globals che sono veramente globali per tutto il tuo programma è il modulo ['__builtin__'] (http://docs.python.org/library/__builtin__.html); tutto ciò che aggiungi al modulo * that * diventa disponibile in tutti i namespace ovunque. –

risposta

71

Python fornisce al programmatore un gran numero di strumenti per l'introspezione dell'ambiente in esecuzione. globals() è solo uno di questi e può essere molto utile in una sessione di debug per vedere quali oggetti contiene effettivamente l'ambito globale.

La logica dietro di esso, ne sono sicuro, è la stessa di quella di utilizzare locals() per vedere le variabili definite in una funzione, o utilizzando dir per vedere il contenuto di un modulo, o gli attributi di un oggetto.

Provenendo da uno sfondo C++, posso capire che queste cose sembrano non necessarie. In un ambiente staticamente collegato, tipizzato staticamente, sarebbero assolutamente. In questo caso, è noto al momento della compilazione esattamente quali variabili sono globali, quali membri avranno un oggetto e anche quali nomi verranno esportati da un'altra unità di compilazione.

In un linguaggio dinamico, tuttavia, queste cose non sono fisse; possono cambiare a seconda di come viene importato il codice o anche durante il tempo di esecuzione. Almeno per questo motivo, avere accesso a questo tipo di informazioni in un debugger può essere inestimabile.

+9

+1. Inoltre, il dizionario restituito da 'globals' può essere modificato (probabilmente una funzionalità lasciata agli esperti). Rilevante è anche questa citazione di [Dive Into Python] (http://www.diveintopython.net/html_processing/locals_and_globals.html) "Usando le funzioni' locals' e 'globals', puoi ottenere il valore di variabili arbitrarie in modo dinamico, fornendo il nome della variabile come una stringa Questo rispecchia la funzionalità della funzione 'getattr', che consente di accedere a funzioni arbitrarie in modo dinamico fornendo il nome della funzione come stringa." –

+1

Non dire che la tua risposta fosse migliore di quella degli altri, ma per me lo era. Grazie, credo di aver bisogno di calmarmi e di ricordare che Python non è C++ :) E grazie anche a tutti gli altri che rispondono, chiarito abbastanza spesso. –

+0

Cambiare elementi in locals() di solito non funziona. La maggior parte delle funzioni Python non ha un dettato per i locali - così quando chiamate i locals() costruisce un dict dei valori correnti dei locals; cambiare quel dettato non riflette la gente del posto. Ci sono stati casi in cui le funzioni facevano cose come "import * da xyz" (non più permesso) - che imposta i locals con nomi sconosciuti al momento della compilazione; quelle funzioni sono state compilate con una vera gente del posto, molto tempo fa, * tutte le funzioni avevano una gente del posto, e hanno eliminato gradualmente la necessità di farlo, non so a quali condizioni hai ora un dittico. – greggo

5

globals() è utile per eval() - se si desidera valutare un codice che fa riferimento a variabili in ambito, tali variabili saranno in globali o locali.


Per espandere un po ', la funzione built-eval() interpreterà una stringa di codice Python dato ad essa. La firma è: eval(codeString, globals, locals), e si dovrebbe utilizzare in questo modo:

def foo(): 
    x = 2 
    y = eval("x + 1", globals(), locals()) 
    print("y=" + y) # should be 3 

Questo funziona, perché l'interprete ottiene il valore della x dalla locals() dict di variabili. Ovviamente puoi fornire il tuo dettato di variabili da valutare.

+1

Downvoter: per favore spiegami in un commento. –

+0

Non ero l'unico downvoting, ma non aveva senso, potresti fornire un codice di esempio per una comprensione più semplice? –

+0

Certo, ho ampliato la mia risposta. –

7

È possibile passare il risultato di globals() e locals() ai comandi eval, execfile e __import__. In questo modo si crea un ambiente limitato per il funzionamento di tali comandi.

Pertanto, queste funzioni esistono per supportare altre funzioni che beneficiano di un ambiente potenzialmente diverso dal contesto corrente. Ad esempio, è possibile chiamare globals() quindi rimuovere o aggiungere alcune variabili prima di chiamare una di queste funzioni.

30

È utile anche quando è necessario chiamare una funzione utilizzando il nome della stringa della funzione. Ad esempio:

def foo(): 
    pass 

function_name_as_string = 'foo' 

globals()[function_name_as_string]() # foo(). 
+3

Vedo. È una buona pratica? –

+0

Cosa succede se la funzione ha molti parametri come, def foo (a, b, c = false). Come passare questi parametri a globals() – ksooklall

+0

@ksooklall Si passa alla funzione come al solito: con 'def foo (* args): print (" hw ", * args)' si può fare: 'globals() [ 'foo']() 'o' globals() ['foo'] ('reason', 42) 'ecc. – Tino

0

Può essere utile in 'dichiarative python'.Ad esempio, nel testo sotto FooDef e BarDef sono le classi utilizzate per definire una serie di strutture di dati che vengono poi utilizzate da qualche pacchetto come input o dalla sua configurazione. Ciò ti consente molta flessibilità in ciò che è il tuo input, e non hai bisogno di scrivere un parser.

# FooDef, BarDef are classes 

Foo_one = FooDef("This one", opt1 = False, valence = 3) 
Foo_two = FooDef("The other one", valence = 6, parent = Foo_one) 

namelist = [] 
for i in range(6): 
    namelist.append("nm%03d"%i) 

Foo_other = FooDef("a third one", string_list = namelist) 

Bar_thing = BarDef((Foo_one, Foo_two), method = 'depth-first') 

Si noti che questo file di configurazione utilizza un ciclo per costruire una lista di nomi che fanno parte della configurazione di Foo_other. Quindi, questo linguaggio di configurazione ha un preprocessore molto potente, con una libreria run-time disponibile. Nel caso in cui si desideri, ad esempio, trovare un registro complesso o estrarre elementi da un file zip e decodificarli in base64, come parte della generazione della configurazione (questo approccio non è raccomandato, ovviamente, per i casi in cui l'input può provenire da fonte non attendibile ...)

il pacchetto di legge la configurazione utilizzando qualcosa di simile al seguente:

conf_globals = {} # make a namespace 
# Give the config file the classes it needs 
conf_globals['FooDef']= mypkgconfig.FooDef # both of these are based ... 
conf_globals['BarDef']= mypkgconfig.BarDef # ... on .DefBase 

fname = "user.conf" 
try: 
    exec open(fname) in conf_globals 
except Exception: 
    ...as needed... 
# now find all the definitions in there 
# (I'm assuming the names they are defined with are 
# significant to interpreting the data; so they 
# are stored under those keys here). 

defs = {} 
for nm,val in conf_globals.items(): 
    if isinstance(val,mypkgconfig.DefBase): 
     defs[nm] = val 

Così, finalmente arrivando al punto, globals() è utile, quando si utilizza un tale pacchetto, se si desidera coniare una serie di definizioni proceduralmente:

for idx in range(20): 
    varname = "Foo_%02d" % i 
    globals()[varname]= FooDef("one of several", id_code = i+1, scale_ratio = 2**i) 

Ciò equivale alla scrittura

Foo_00 = FooDef("one of several", id_code = 1, scale_ratio=1) 
Foo_01 = FooDef("one of several", id_code = 2, scale_ratio=2) 
Foo_02 = FooDef("one of several", id_code = 3, scale_ratio=4) 
... 17 more ... 

Un esempio di un pacchetto che ottiene il suo ingresso raccogliendo un gruppo di definizioni di un modulo pitone è CAPI (Python-lex-yacc) http://www.dabeaz.com/ply/ - in quel caso la gli oggetti sono per lo più oggetti funzione, ma anche i metadati dagli oggetti funzione (i loro nomi, docstring e ordine di definizione) fanno parte dell'input. Non è un buon esempio per l'uso di globals(). Inoltre, viene importato dalla 'configurazione' - quest'ultima è un normale script python - piuttosto che viceversa.

Ho usato 'declarative python' su alcuni progetti su cui ho lavorato e ho avuto occasione di usare globals() durante la scrittura di configurazioni per questi. Si potrebbe certamente sostenere che ciò è dovuto a un punto debole nel modo in cui è stato progettato il "linguaggio" di configurazione. L'uso di globals() in questo modo non produce risultati molto chiari; solo risultati che potrebbero essere più facili da mantenere rispetto alla scrittura di una dozzina di dichiarazioni quasi identiche.

Si può anche usare per dare variabili importanza all'interno del file di configurazione, secondo i loro nomi:

# All variables above here starting with Foo_k_ are collected 
# in Bar_klist 
# 
foo_k = [ v for k,v in globals().items() if k.startswith('Foo_k_')] 
Bar_klist = BarDef(foo_k , method = "kset") 

Questo metodo potrebbe essere utile per qualsiasi modulo python che definisce un sacco di tavoli e delle strutture, per semplificare l'aggiunta di elementi ai dati, senza dover mantenere anche i riferimenti.

Problemi correlati