2009-06-25 11 views
29

Considere la siguiente:Obtener un diccionario de todas las variables actualmente en su alcance y sus valores

globalVar = 25 

def myfunc(paramVar): 
    localVar = 30 
    print "Vars: {globalVar}, {paramVar}, {localVar}!".format(**VARS_IN_SCOPE) 

myfunc(123) 

Dónde VARS_IN_SCOPE es el dict estoy después de eso contendría globalVar, paramVar y localVar, entre otras cosas.

Quisiera poder básicamente hacer referencia a todas las variables que se encuentran actualmente en el alcance dentro de la cadena. Por lo tanto el resultado esperado sería:

Vars: 25, 123, 30

puedo lograr esto pasando **dict(globals().items() + locals().items())-format(). ¿Esto siempre es correcto o hay algunos casos de esquina que esta expresión manejaría incorrectamente?

Reescrito para aclarar la pregunta.

+0

¿Por qué querrías hacer eso? Lo más probable es que haya una mejor manera de hacer lo que sea que intentes hacer. –

+0

Pensé que el fragmento lo dejaría en claro. Me gustaría interpolar las variables dentro de las cadenas. Por supuesto, podría haber una mejor manera. Por favor, siéntase libre de sugerir uno como respuesta. –

+0

Lo sentimos, el fragmento no explica ** por qué ** necesita tal cosa. Además, los parámetros son simplemente locales, no es un ámbito separado. –

Respuesta

32

mejor manera de combinar dos predice que estás haciendo (con variables globales locales preponderantes) es dict(globals(), **locals()).

Lo que le falta al enfoque de fusionar globales y locales es (a) construcciones internas (me imagino que es deliberado, es decir, no se piensa en construcciones como "variables" ... pero, PODRÍAN ser, si así lo desea ! -), y (b) si está en una función anidada, cualquier variable que sea local para adjuntar funciones (ninguna forma realmente buena de obtener un dict con todos esos, plus - solo aquellos explícitamente accedidos en la función anidada, es decir, "variables libres" de la misma, de todos modos sobreviven como células en un cierre).

Imagino que estos problemas no son un gran problema para su uso previsto, pero mencionó "casos de esquina" ;-). Si necesita cubrirlos, hay formas de obtener los integrables (eso es fácil) y (no tan fácil) todas las celdas (variables de las funciones adjuntas que menciona explícitamente en la función anidada - thefunction.func_code.co_freevars para obtener los nombres, thefunction.func_closure para obtener las celdas, cell_contents en cada celda para obtener su valor). (Pero, recuerde, esas solo serán variables de las funciones adjuntas que son explícitamente accedidas al en el código de su función anidada!).

+0

Es extraño que no puedas obtener todas las variables desde dentro de una función anidada. ¿Alguien sabe por qué 'locals()' no funcionará? ¡Parece que debería! – sudo

7

¿Hace esto lo que pretendía?

d = dict(globals()) 
d.update(locals()) 

Si leo la documentación correctamente, se crea una copia de la globals() dict, a continuación, se sobrescribe cualquier duplicado y de inserción de nuevas entradas de la locals() dict (ya que el locals() deberían tener preferencia dentro de su ámbito de aplicación, de todos modos)


No he tenido ningún suerte en conseguir un funcionamiento adecuado para devolver el diccionario completo de variables en el ámbito de la llamando función. Aquí está el código (sólo se utiliza pprint para dar formato a la salida muy bien para el SO):

from pprint import * 

def allvars_bad(): 
    fake_temp_var = 1 
    d = dict(globals()) 
    d.update(locals()) 
    return d 

def foo_bad(): 
    x = 5 
    return allvars_bad() 

def foo_good(): 
    x = 5 
    fake_temp_var = "good" 
    d = dict(globals()) 
    d.update(locals()) 
    return d 

pprint (foo_bad(), width=50) 
pprint (foo_good(), width=50) 

y la salida:

{'PrettyPrinter': <class pprint.PrettyPrinter at 0xb7d316ec>, 
'__builtins__': <module '__builtin__' (built-in)>, 
'__doc__': None, 
'__file__': 'temp.py', 
'__name__': '__main__', 
'__package__': None, 
'allvars_bad': <function allvars_bad at 0xb7d32b1c>, 
'd': <Recursion on dict with id=3084093748>, 
'fake_temp_var': 1, 
'foo_bad': <function foo_bad at 0xb7d329cc>, 
'foo_good': <function foo_good at 0xb7d32f0c>, 
'isreadable': <function isreadable at 0xb7d32c34>, 
'isrecursive': <function isrecursive at 0xb7d32c6c>, 
'pformat': <function pformat at 0xb7d32bc4>, 
'pprint': <function pprint at 0xb7d32b8c>, 
'saferepr': <function saferepr at 0xb7d32bfc>} 
{'PrettyPrinter': <class pprint.PrettyPrinter at 0xb7d316ec>, 
'__builtins__': <module '__builtin__' (built-in)>, 
'__doc__': None, 
'__file__': 'temp.py', 
'__name__': '__main__', 
'__package__': None, 
'allvars_bad': <function allvars_bad at 0xb7d32b1c>, 
'd': <Recursion on dict with id=3084093884>, 
'fake_temp_var': 'good', 
'foo_bad': <function foo_bad at 0xb7d329cc>, 
'foo_good': <function foo_good at 0xb7d32f0c>, 
'isreadable': <function isreadable at 0xb7d32c34>, 
'isrecursive': <function isrecursive at 0xb7d32c6c>, 
'pformat': <function pformat at 0xb7d32bc4>, 
'pprint': <function pprint at 0xb7d32b8c>, 
'saferepr': <function saferepr at 0xb7d32bfc>, 
'x': 5} 

Nótese que en la segunda salida, hemos sobrescrito fake_temp_var, y X es presente; la primera salida solo incluía los vars locales dentro del alcance de allvars_bad.

Si quiere acceder al ámbito de variable completo, no puede poner los locales() dentro de otra función.


Yo sospechaba que había algún tipo de objeto de marco, simplemente no sabía dónde buscarlo.

Esto funciona a su especificación, creo:

def allvars_good(offset=0): 
    frame = sys._getframe(1+offset) 
    d = frame.f_globals 
    d.update(frame.f_locals) 
    return d 


def foo_good2(): 
    a = 1 
    b = 2 
    return allvars_good() 

->

{'PrettyPrinter': <class pprint.PrettyPrinter at 0xb7d6474c>, 
'__builtins__': <module '__builtin__' (built-in)>, 
'__doc__': None, 
'__file__': 'temp.py', 
'__name__': '__main__', 
'__package__': None, 
'a': 1, 
'allvars_bad': <function allvars_bad at 0xb7d65b54>, 
'allvars_good': <function allvars_good at 0xb7d65a04>, 
'b': 2, 
'foo_bad': <function foo_bad at 0xb7d65f44>, 
'foo_good': <function foo_good at 0xb7d65f7c>, 
'foo_good2': <function foo_good2 at 0xb7d65fb4>, 
'isreadable': <function isreadable at 0xb7d65c6c>, 
'isrecursive': <function isrecursive at 0xb7d65ca4>, 
'pformat': <function pformat at 0xb7d65bfc>, 
'pprint': <function pprint at 0xb7d65bc4>, 
'saferepr': <function saferepr at 0xb7d65c34>, 
'sys': <module 'sys' (built-in)>} 
+0

Para responder a su pregunta, no sé :) Esto es en realidad lo que me gustaría averiguar, ya sea que solo combinar los dos sea lo correcto. –

+0

Sí, lamentablemente los locales() tienen que estar ahí. Similar con globals(): debe estar en el mismo módulo para funcionar. Me pregunto si podría usarse algún truco de sys._getframe() en su lugar. –

2

Se podría hacer su propia:

allvars = dict() 
allvars.update(globals()) 
allvars.update(locals()) 

o combinar las primeras dos líneas:

allvars = dict(globals()) 
allvars.update(locals()) 
1

La interpolación en cadenas funciona de la manera más simple posible. Solo haz una lista de tus variables. Python comprueba locales y globales por ti.

globalVar = 25 

def myfunc(paramVar): 
    localVar = 30 
    print "Vars: %d, %d, %d!" % (globalVar, paramVar, localVar) 

myfunc(123) 
+0

Eso no es interpolación. http://en.wikipedia.org/wiki/Variable_(computer_science)#Interpolation - Python no lo tiene como tal, pero con la función .format() puede acercarse bastante. –

+0

Y en caso de que se pregunte por qué no me gusta%, piense en algo como esto: print "{path} /myscript.py --input {path}/file1 --output {path}/file2" .format (** locals ()) - con "%" necesitaría pasar el camino tres veces. Con muchas variables, esto se convierte en una pesadilla completa de mantener. –

+0

@romkyns: Eso no es así. El operador de cadena '%' puede tomar un argumento dict sin necesidad de descomprimirlo con '**' como 'format' lo hace: print"% (path) s/myscript.py --input% (path) s/file1 --output% (path) s/file2 "% locals() –

2
globalVar = 25 

def myfunc(paramVar): 
    localVar = 30 
    all_vars = locals.copy() 
    all_vars.update(globals()) 
    print "Vars: {globalVar}, {paramVar}, {localVar}!".format(all_vars) 

myfunc(123) 
Cuestiones relacionadas