Python: ¿Cómo puedo ejecutar eval() en el ámbito local de una función
scope (2)
Intento usar eval () en un ámbito local de una función. Sin embargo, siempre se evalúa en el ámbito global.
Ejemplos autocontenidos:
1- Este código funciona:
var1 = 1
var2 = 2
var3 = 3
myDict = dict((name, eval(name)) for name in ["var1",
"var2",
"var3"])
print(myDict["var1"])
2- Lanza
NameError
para
lvar1
def test1():
lvar1 = 1
lvar2 = 2
lvar3 = 3
myDict = dict((name, eval(name)) for name in ["lvar1",
"lvar2",
"lvar3"])
print(myDict["lvar1"])
3- Mismo resultado que 2.
def test2():
lvar1 = 1
lvar2 = 2
lvar3 = 3
myDict = dict((name, eval(name), locals()) for name in ["lvar1",
"lvar2",
"lvar3"])
print(myDict["lvar1"])
En primer lugar, es importante leer esto :
El argumento de expresión se analiza y evalúa como una expresión de Python (técnicamente hablando, una lista de condiciones) utilizando los diccionarios globales y locales como espacio de nombres global y local. Si el diccionario
''__builtins__''
está presente y carece de''__builtins__''
, las globales actuales se copian en globales antes de analizar la expresión. Esto significa que la expresión normalmente tiene acceso completo al módulo estándar__builtin__
y se propagan entornos restringidos. Si se omite el diccionario local, el valor predeterminado es el diccionario global. Si se omiten ambos diccionarios, la expresión se ejecuta en el entorno donde se llama aeval()
. El valor de retorno es el resultado de la expresión evaluada`.
Para comenzar, es importante tener en cuenta que una expresión generadora tiene su propio alcance (también es cierto para una comprensión dict), por lo tanto, tiene su propio diccionario
locals()
.
-
Esto funcionó porque en el ámbito global, tanto dict global
globals()
comolocals()
apuntan al mismo diccionario, por lo tanto, el constructor dict puede acceder a esas variables. -
Aquí estamos nuevamente llamando a
eval()
singlobals()
ylocals()
dict, por lo tanto, termina usando el alcance global y su propio alcance local (que está vacío) y no hay ninguna variable disponible en ninguno de estos ámbitos. -
Recuerde que los generadores tienen su propio alcance, por lo que llamar a los
locals()
aquí apenas hace ninguna diferencia, es un dict vacío.
Solución:
def test1():
lvar1 = 1
lvar2 = 2
lvar3 = 3
test1_locals = locals()
myDict = dict((name, eval(name, test1_locals)) for name in ["lvar1",
"lvar2",
"lvar3"])
print myDict
print(myDict["lvar1"])
Esto funcionó porque capturamos los
locals()
de test1
locals()
en una variable y luego usamos ese diccionario dentro de la comprensión del diccionario, por lo que ahora tiene acceso a esas variables.
Guarde el resultado de la llamada
locals()
(o
vars()
) para devolver el alcance local de la función.
De lo contrario, los
locals()
dentro de la expresión del generador devolverán el alcance local de gen-expr.
def test3():
lvar1 = 1
lvar2 = 2
lvar3 = 3
scope = locals()
myDict = dict((name, eval(name, scope)) for name in [
"lvar1", "lvar2", "lvar3"])
print(myDict["lvar1"])
Por cierto, no necesita una comprensión explícita para construir ese dict:
# copy() avoids quirky, unexpected updates if something else (like a debugger)
# accesses locals() or f_locals
myDict = locals().copy() # or vars().copy()