example - python3 exec
¿Por qué el ejecutor no funciona en una función con una subfunción? (5)
Aunque en Python parece que las variables locales están almacenadas en un diccionario locals()
, generalmente no lo son. En su lugar, se almacenan principalmente en la pila y se accede por índice. Esto hace que la búsqueda de variables locales sea más rápida que si tuviera que hacer una búsqueda de diccionario todo el tiempo. Si usa la función locals()
, entonces lo que obtiene es un diccionario nuevo creado a partir de todas las variables locales, y es por eso que la asignación a locals()
generalmente no funciona.
Hay un par de excepciones a este escenario:
Cuando utiliza un exec
no calificado dentro de una función, Python desactiva la optimización y usa un diccionario real para las variables locales. Eso significa que puede crear o actualizar variables desde dentro del exec
, pero también significa que todo el acceso variable local en esa función se ejecutará más lentamente.
La otra excepción es que cuando anida funciones, la función interna puede acceder a las variables locales en el ámbito de la función externa. Cuando lo hace, la variable se almacena en un objeto ''celda'' en lugar de almacenarse en la pila. El nivel adicional de direccionamiento indirecto hace que todo el uso de las variables delimitadas sea más lento ya sea que acceda a ellos desde la función interna o externa.
La captura que ha encontrado es que estas dos excepciones a cómo se almacenan normalmente las variables locales son incompatibles. No puede tener una variable almacenada en un diccionario y acceder a ella a través de una referencia de celda al mismo tiempo. Python 2.x lo soluciona al no permitir el uso del exec, incluso en casos como este en los que no intenta utilizar ninguna variable con ámbito.
Parece que no puede usar exec en una función que tiene una subfunción ...
¿Alguien sabe por qué este código de Python no funciona? Recibo un error en el ejecutivo en test2. Además, sé que los ejecutivos no son un buen estilo, pero créanme, estoy usando el ejecutivo por una razón apropiada. No lo usaría de otra manera.
#!/usr/bin/env python
#
def test1():
exec(''print "hi from test1"'')
test1()
def test2():
"""Test with a subfunction."""
exec(''print "hi from test2"'')
def subfunction():
return True
test2()
EDITAR: reduje el error a tener una función en una subfunción. No tiene nada que ver con la palabra clave raise.
Correcto. No puede usar exec en una función que tenga una subfunción, a menos que especifique un contexto. De los documentos:
Si se usa exec en una función y la función contiene un bloque anidado con variables libres, el compilador generará un SyntaxError a menos que el ejecutivo especifique explícitamente el espacio de nombres local para el ejecutivo. (En otras palabras, "exec obj" sería ilegal, pero "exec obj in ns" sería legal.)
Hay una buena razón para esto que probablemente entendería si no fuera el domingo por la noche. Ahora, la siguiente pregunta: ¿Por qué estás usando exec? Rara vez es necesario. Usted dice que tiene una buena razón. Me siento escéptico sobre eso. ;) Si tiene una buena razón, le diré la solución. :-PAG
Oh, bueno, aquí está de todos modos:
def test2():
"""Test with a subfunction."""
exec ''print "hi from test2"'' in globals(), locals()
def subfunction():
return True
El error parece ser bastante obvio para mí:
SyntaxError: unqualified exec is not allowed in function ''test2'' it contains a nested function with free variables
Ver pep 227 para más información: http://www.python.org/dev/peps/pep-0227/
Eso funciona bien en Python 3.1.3, después de modificar la declaración de impresión para usar la función de impresión.
En Python 2.6, produce SyntaxError: unqualified exec is not allowed in function ''test2'' it contains a nested function with free variables
, no creo que sea un error.
Este es un caso bastante interesante:
>>> def func():
... exec(''print "hi from func"'')
... def subfunction():
... return True
...
File "<stdin>", line 2
SyntaxError: unqualified exec is not allowed in function ''func'' because
it contains a nested function with free variables
La razón por la que esto no funciona de hecho es que la subfunction
contiene una variable libre, y dado que en Python 2, el exec
podría modificar teóricamente los locales en el ámbito contenedor, sería imposible decidir si la variable debería estar vinculada a la global o el alcance de la función principal. Uno de los versos del Zen de Python es "Ante la ambigüedad, rechaza la tentación de adivinar". y esto es lo que hace Python 2.
Ahora la pregunta es: ¿qué es esta variable independiente? Bueno, es el True
!
De hecho, es reproducible con None
:
>>> def func():
... exec(''print "hi from func"'')
... def subfunction():
... return None
...
File "<stdin>", line 2
SyntaxError: unqualified exec is not allowed in function ''test2'' because it contains a nested
function with free variables
Aunque no se puede asignar None
, y se considera como una constante en el bytecode, el analizador con errores cree que es una variable independiente aquí.
Pero si lo reemplazas con 1
y funciona sin problemas:
>>> def test2():
... exec(''print "hi from func"'')
... def subfunction():
... return 1
...
>>>
Para evitar este error, especifique explícitamente los globales y posiblemente los locales que deben ser utilizados por el exec
, por ejemplo:
>>> def test2():
... exec ''print "hi from test2"'' in {}
... def subfunction():
... return None
...
>>>
En Python 3, el exec
es simplemente una función simple y no es manejado especialmente por el analizador o el compilador de códigos de bytes. En Python 3, el exec
no puede volver a enlazar los nombres locales de la función y, por lo tanto, este SyntaxError y la ambigüedad no existen.
Un caso peculiar en Python 2 vs 3 compatibilidad es que, mientras que la documentación de Python 2.7 establece que
La forma
exec(expr, globals)
es equivalente aexec expr in globals
, mientras que la formaexec(expr, globals, locals)
es equivalente aexec expr in globals, locals
. La forma de tupla delexec
proporciona compatibilidad con Python 3, donde elexec
es una función en lugar de una declaración.
La forma de tupla no siempre ha sido 100% compatible, ya que hubo un error en el manejo de exec
en funciones con funciones anidadas (problema 21591) ; hasta Python 2.7.8 el siguiente código podría haber arrojado una excepción:
def func():
exec(''print "hi from test2"'', {})
def subfunction():
return None
Esto se solucionó en Python 2.7.9 y ya no se lanza.