literal_eval ast python eval python-internals

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}