python scope eval

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 a eval() . 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() .

  1. Esto funcionó porque en el ámbito global, tanto dict global globals() como locals() apuntan al mismo diccionario, por lo tanto, el constructor dict puede acceder a esas variables.

  2. Aquí estamos nuevamente llamando a eval() sin globals() y locals() 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.

  3. 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()