ast - python eval
alcance de la funciĆ³n eval en python (2)
Esto ocurre porque la expresión del generador tiene un alcance diferente a la función :
>>> def test():
i, j, k = range(1, 4)
return dict((j, locals()) for _ in range(i))
>>> test()
{2: {''.0'': <listiterator object at 0x02F50A10>, ''j'': 2, ''_'': 0}}
El uso de j
dentro del ámbito lo vincula desde la función, ya que es el ámbito más cercano, pero i
y k
no están vinculados localmente (ya que k
no está referenciado y i
solo se usa para crear el range
).
Tenga en cuenta que puede evitar este problema con:
return dict(i=i, j=j, k=k)
o un diccionario literal:
return {''i'': i, ''j'': j, ''k'': k}
Considere el siguiente ejemplo:
i=7
j=8
k=10
def test():
i=1
j=2
k=3
return dict((name,eval(name)) for name in [''i'',''j'',''k''])
Vuelve:
>>> test()
{''i'': 7, ''k'': 10, ''j'': 8}
¿Por qué eval no tiene en cuenta las variables definidas dentro de la función? Desde la documentación, opcionalmente puede pasar un global y un diccionario local. ¿Qué significa? Finalmente, ¿cómo puedo modificar este pequeño estuche para que funcione?
Los generadores se implementan como ámbitos de función :
El alcance de los nombres definidos en un bloque de clase se limita al bloque de clase; no se extiende a los bloques de código de los métodos, esto incluye expresiones generadoras ya que se implementan utilizando un ámbito de función .
Entonces, el generador dentro del constructor dict()
tiene su propio diccionario locals()
. Ahora echemos un vistazo al código fuente de Py_eval
, especialmente cuando globals()
y locals()
son None:
if (globals == Py_None) {
globals = PyEval_GetGlobals();
if (locals == Py_None)
locals = PyEval_GetLocals();
}
Por lo tanto, para su ejemplo, PyEval_GetLocals()
estará vacío en el momento en que el bucle se esté ejecutando y globals()
será el diccionario global. Tenga en cuenta que i
, j
y k
definidos dentro de la función no están en el ámbito local del generador, sino que están en su ámbito de aplicación:
>>> dict((name,eval(name, globals(), {})) for name in [''i'', ''j'', ''k''])
{''i'': 7, ''k'': 10, ''j'': 8}