2012-10-02 14 views
52

¿Cuál es el motivo de tener la función globals() en Python? Solo devuelve el diccionario de variables globales, que ya son globales, por lo que se pueden usar en cualquier parte ... Lo pido solo por curiosidad, tratando de aprender Python.Motivo de globals() en 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() 

Realmente no veo el punto aquí? Sólo el tiempo que lo necesitaría, era si tuviera variables locales y globales, con el mismo nombre para ambos

def F(): 
    global x 
    x = 1 

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

F() 
G() 

pero nunca se debe ejecutar en un problema de tener dos variables con el mismo nombre, y la necesidad de utilizar ambos dentro del mismo alcance.

+2

"Pero nunca se debe tener el problema de tener dos variables con el mismo nombre y la necesidad de usarlas dentro del mismo ámbito". No puedo seguir este pensamiento. Esa es toda la razón para espacios de nombres separados, que tiene variables con el mismo nombre en diferentes ámbitos. Cuando trabaja con dos de ellos, los nombres duplicados son algo natural, pero no un problema, ya que puede prefijarlos. – Michael

+0

Bueno, vengo de la familia C++, así que no estoy seguro acerca de la gente de Python, pero por lo que puedo pensar, no debería tener una variable ** global ** que no tenga un nombre único. Seguro que habrá variables con el mismo nombre, en el mismo ámbito, esa fue una frase estúpida de mí, pero no globales con los mismos nombres que los locales. Ahí es cuando usaría espacios de nombres para los locales ... Pero no sé, si tú lo dices. –

+3

@Mahi: 'globals' es quizás un poco engañoso. 'globals()' es esencialmente el 'locals()' de un módulo.El Python más cercano a los globales que son verdaderamente globales para todo su programa es el módulo ['__builtin__'] (http://docs.python.org/library/__builtin__.html); cualquier cosa que agregue a * ese * módulo estará disponible en todos los espacios de nombres en todas partes. –

Respuesta

71

Python proporciona al programador una gran cantidad de herramientas para introspectar el entorno de ejecución. globals() es solo una de ellas, y puede ser muy útil en una sesión de depuración para ver qué objetos contiene en realidad el alcance global.

La razón detrás de esto, estoy seguro, es la misma que usar locals() para ver las variables definidas en una función, o usar dir para ver el contenido de un módulo o los atributos de un objeto.

Viniendo de un fondo de C++, puedo entender que estas cosas parecen innecesarias. En un entorno estáticamente vinculado, estáticamente estáticamente tipado, lo estarían absolutamente. En ese caso, en el momento de la compilación se conoce exactamente qué variables son globales y qué miembros tendrá un objeto, e incluso qué nombres exporta otra unidad de compilación.

En un lenguaje dinámico, sin embargo, estos elementos no son correctos; pueden cambiar dependiendo de cómo se importa el código, o incluso durante el tiempo de ejecución. Por esa razón, al menos, tener acceso a este tipo de información en un depurador puede ser invaluable.

+9

+1. Además, el diccionario devuelto por 'globals' se puede modificar (probablemente sea una mejor opción para los expertos). También es relevante esta cita de [Dive Into Python] (http://www.diveintopython.net/html_processing/locals_and_globals.html) "Usando las funciones' locals' y 'globals', puede obtener el valor de las variables arbitrarias dinámicamente, proporcionando el nombre de la variable como una cadena. Esto refleja la funcionalidad de la función 'getattr', que le permite acceder a funciones arbitrarias de forma dinámica al proporcionar el nombre de la función como una cadena. –

+1

No diciendo que tu respuesta fue mejor que la de los demás, pero para mí fue así. Gracias, supongo que necesito calmarme y recordar que Python no es C++ :) Y gracias a todos los demás que respondieron también, aclararon bastante. –

+0

Cambiar elementos en locales() generalmente no funciona. La mayoría de las funciones de python no tienen un dict para los locales, por lo que cuando llamas a locals() construye un dict de los valores actuales de los locales; cambiar ese dict no refleja a los lugareños. Hubo casos en los que las funciones hicieron cosas como "importar * desde xyz" (ya no está permitido): eso establece locals con nombres desconocidos en tiempo de compilación; esas funciones fueron compiladas con un dict local real, hace mucho tiempo, * todas las funciones tenían un dict real de los lugareños, y han eliminado la necesidad de eso, no sé bajo qué condiciones tienes un dict ahora. – greggo

5

globals() es útil para eval() - si quiere evaluar algún código que se refiera a variables en el alcance, esas variables estarán en globales o locales.


Para ampliar un poco, la función incorporada eval() interpretará una cadena de código Python que se le da. La firma es: eval(codeString, globals, locals), y lo utilizaría como tan:

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

Esto funciona, porque el intérprete obtiene el valor de x del locals() dict de variables. Por supuesto, puede proporcionar su propio dict de variables para eval.

+1

Downvoter: por favor explique en un comentario. –

+0

No fui el que menos votó, pero eso realmente no tenía sentido, ¿podría darme un código de ejemplo para facilitar la comprensión? –

+0

Claro, he expandido mi respuesta. –

7

puede pasar el resultado de globals() y locals() a los comandos eval, execfile y __import__. Hacerlo crea un entorno restringido para que esos comandos funcionen.

Por lo tanto, estas funciones existen para admitir otras funciones que se benefician de tener un entorno potencialmente diferente del contexto actual. Por ejemplo, puede llamar al globals() y luego eliminar o agregar algunas variables antes de llamar a una de esas funciones.

30

También es útil cuando necesita llamar a una función usando el nombre de la cadena de la función. Por ejemplo:

def foo(): 
    pass 

function_name_as_string = 'foo' 

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

Ya veo. ¿Es eso una buena práctica? –

+0

¿Qué pasa si la función tiene muchos parámetros como, def foo (a, b, c = false). Cómo pasaría esos parámetros a globals() – ksooklall

+0

@ksooklall Lo pasa a la función como de costumbre: con 'def foo (* args): print (" hw ", * args)' puede hacer: 'globals() [ 'foo']() 'o' globals() ['foo'] ('reason', 42) 'etc. – Tino

0

Puede ser útil en 'declarative python'.Por ejemplo, en el siguiente FooDef y BarDef son clases usadas para definir una serie de estructuras de datos que luego son utilizadas por algún paquete como su entrada o su configuración. Esto le permite mucha flexibilidad en lo que se refiere a su entrada, y no necesita escribir un analizador.

# 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') 

Tenga en cuenta que este archivo de configuración utiliza un bucle para construir una lista de nombres que son parte de la configuración de Foo_other. Entonces, este lenguaje de configuración viene con un 'preprocesador' muy poderoso, con una biblioteca de tiempo de ejecución disponible. En caso de que quiera, digamos, encontrar un registro complejo, o extraer elementos de un archivo zip y decodificarlos en base64, como parte de la generación de su configuración (este enfoque no es recomendable, por supuesto, para los casos en que la entrada puede ser de un fuente no confiable ...)

el paquete lee la configuración de usar algo como lo siguiente:

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 

Así que, finalmente llegando al punto, globals() es útil, cuando se utiliza un envase de este tipo, si se quiere acuñar una serie de definiciones procesales:

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

Esto es equivalente a escribir

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 ejemplo de un paquete que obtiene su entrada mediante la recopilación de un montón de definiciones de un módulo de Python es PLY (Python-lex-yacc) http://www.dabeaz.com/ply/ - en ese caso el los objetos son en su mayoría objetos de función, pero los metadatos de los objetos de función (sus nombres, cadenas de documentos y orden de definición) también forman parte de la entrada. No es un buen ejemplo para el uso de globals(). Además, es importado por la 'configuración', siendo esta última una secuencia de comandos python normal, y no al revés.

He usado 'declarative python' en algunos proyectos en los que he trabajado, y he tenido ocasión de usar globals() al escribir configuraciones para ellos. Ciertamente se podría argumentar que esto se debió a una debilidad en la forma en que se diseñó el 'lenguaje' de configuración. El uso de globals() de esta manera no produce resultados muy claros; solo resultados que podrían ser más fáciles de mantener que escribir una docena de declaraciones casi idénticas.

También puede usarlo para dar variables de importancia dentro del archivo de configuración, según sus nombres:

# 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") 

Este método podría ser útil para cualquier módulo pitón que define un montón de mesas y estructuras, para que sea más fácil agregar elementos a los datos, sin tener que mantener las referencias también.

Cuestiones relacionadas