La respuesta corta, o TL; DR
Básicamente, eval
se utiliza para eval luar una sola expresión Python generado dinámicamente, y exec
se utiliza para exec UTE generado dinámicamente código Python sólo por sus efectos secundarios.
eval
y exec
tienen estas dos diferencias:
eval
sólo acepta una sola expresión , exec
puede tomar un bloque de código que tiene las sentencias de Python: bucles, try: except:
, class
y la función / método def
initions y así sucesivamente.
Una expresión en Python es lo que pueda tener como valor en una asignación variable:
a_variable = (anything you can put within these parentheses is an expression)
eval
devuelve el valor de la expresión dada, mientras que exec
ignora el valor de retorno de su código, y siempre devuelve None
(en Python 2 es una declaración y no puede usarse como una expresión, por lo que realmente no devuelve nada).
En las versiones 1.0 - 2.7, exec
era una declaración, porque CPython necesitaba producir un tipo diferente de objeto de código para las funciones que usaba exec
para sus efectos secundarios dentro de la función.
En Python 3, exec
es una función; su uso no tiene efecto en el bytecode compilado de la función donde se usa.
Así básicamente:
>>> a = 5
>>> eval('37 + a') # it is an expression
42
>>> exec('37 + a') # it is an expression statement; value is ignored (None is returned)
>>> exec('a = 47') # modify a global variable as a side effect
>>> a
47
>>> eval('a = 47') # you cannot evaluate a statement
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
a = 47
^
SyntaxError: invalid syntax
El modo compile
in 'exec'
compila cualquier número de declaraciones en un código de bytes que implícitamente siempre devuelve None
, mientras que en el 'eval'
modo compila una sola expresión en código de bytes que devuelve el valor de esa expresión.
>>> eval(compile('42', '<string>', 'exec')) # code returns None
>>> eval(compile('42', '<string>', 'eval')) # code returns 42
42
>>> exec(compile('42', '<string>', 'eval')) # code returns 42,
>>> # but ignored by exec
En el 'eval'
modo (y, por lo tanto, con la eval
función si se pasa una cadena), se compile
genera una excepción si el código fuente contiene declaraciones o cualquier otra cosa más allá de una sola expresión:
>>> compile('for i in range(3): print(i)', '<string>', 'eval')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print(i)
^
SyntaxError: invalid syntax
En realidad, la declaración "eval acepta solo una sola expresión" se aplica solo cuando se pasa una cadena (que contiene el código fuente de Python ) eval
. Luego se compila internamente en bytecode usando compile(source, '<string>', 'eval')
Aquí es de donde realmente viene la diferencia.
Si un code
objeto (que contiene Python código de bytes ) se pasa a la exec
o eval
, que se comportan de forma idéntica , excepto por el hecho de que exec
ignora el valor de retorno, todavía volver None
siempre. Por lo tanto, es posible eval
ejecutar algo que tenga sentencias, si solo compile
lo ingresó en bytecode antes en lugar de pasarlo como una cadena:
>>> eval(compile('if 1: print("Hello")', '<string>', 'exec'))
Hello
>>>
funciona sin problemas, aunque el código compilado contiene sentencias. Todavía regresa None
, porque ese es el valor de retorno del objeto de código devuelto compile
.
En el 'eval'
modo (y, por lo tanto, con la eval
función si se pasa una cadena), se compile
genera una excepción si el código fuente contiene declaraciones o cualquier otra cosa más allá de una sola expresión:
>>> compile('for i in range(3): print(i)', '<string>'. 'eval')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print(i)
^
SyntaxError: invalid syntax
La respuesta más larga, también conocida como los detalles sangrientos
exec
y eval
La exec
función (que era una declaración en Python 2 ) se usa para ejecutar una declaración o programa creado dinámicamente:
>>> program = '''
for i in range(3):
print("Python is cool")
'''
>>> exec(program)
Python is cool
Python is cool
Python is cool
>>>
La eval
función hace lo mismo para una sola expresión , y devuelve el valor de la expresión:
>>> a = 2
>>> my_calculation = '42 * a'
>>> result = eval(my_calculation)
>>> result
84
exec
y eval
tanto aceptar el programa / expresión para ser ejecutado ya sea como una str
, unicode
o bytes
que contiene objeto de código fuente, o como un code
objeto que contiene Python bytecode.
Si se pasó un str
/ unicode
/ bytes
código fuente que contiene exec
, se comporta de manera equivalente a:
exec(compile(source, '<string>', 'exec'))
y eval
se comporta de manera similar a:
eval(compile(source, '<string>', 'eval'))
Dado que todas las expresiones se pueden usar como declaraciones en Python (estos se llaman Expr
nodos en la gramática abstracta de Python ; lo contrario no es cierto), siempre se puede usar exec
si no necesita el valor de retorno. Es decir, puede usar cualquiera eval('my_func(42)')
o exec('my_func(42)')
, la diferencia es que eval
devuelve el valor devuelto por my_func
y lo exec
descarta:
>>> def my_func(arg):
... print("Called with %d" % arg)
... return arg * 2
...
>>> exec('my_func(42)')
Called with 42
>>> eval('my_func(42)')
Called with 42
84
>>>
De los 2, sólo se exec
acepta el código fuente que contiene las declaraciones, como def
, for
, while
, import
, o class
, la instrucción de asignación (aka a = 42
), o programas enteros:
>>> exec('for i in range(3): print(i)')
0
1
2
>>> eval('for i in range(3): print(i)')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print(i)
^
SyntaxError: invalid syntax
Ambos exec
y eval
aceptan 2 argumentos posicionales adicionales - globals
y locals
- que son los ámbitos de variables globales y locales que ve el código. Estos valores predeterminados para globals()
y locals()
dentro del alcance que llamó exec
o eval
, pero cualquier diccionario se puede usar para globals
y mapping
para cualquier locals
(incluido, dict
por supuesto). Estos pueden usarse no solo para restringir / modificar las variables que ve el código, sino que a menudo también se usan para capturar las variables que exec
crea el código uted:
>>> g = dict()
>>> l = dict()
>>> exec('global a; a, b = 123, 42', g, l)
>>> g['a']
123
>>> l
{'b': 42}
(Si se visualiza el valor de la totalidad g
, sería mucho más tiempo, porque exec
y eval
añadir módulo de los muebles empotrados como __builtins__
a las variables globales de forma automática si no se encuentra).
En Python 2, la sintaxis oficial para la exec
declaración es en realidad exec code in globals, locals
, como en
>>> exec 'global a; a, b = 123, 42' in g, l
Sin embargo, la sintaxis alternativa exec(code, globals, locals)
siempre ha sido aceptada también (ver más abajo).
compile
El compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
incorporado puede usarse para acelerar invocaciones repetidas del mismo código con exec
o eval
compilando la fuente en un code
objeto de antemano. El mode
parámetro controla el tipo de fragmento de código que compile
acepta la función y el tipo de código de bytes que produce. Las opciones son 'eval'
, 'exec'
y 'single'
:
'eval'
el modo espera una sola expresión, y producirá un código de bytes que cuando se ejecute devolverá el valor de esa expresión :
>>> dis.dis(compile('a + b', '<string>', 'eval'))
1 0 LOAD_NAME 0 (a)
3 LOAD_NAME 1 (b)
6 BINARY_ADD
7 RETURN_VALUE
'exec'
acepta cualquier tipo de construcciones de python desde expresiones individuales hasta módulos completos de código, y las ejecuta como si fueran declaraciones de nivel superior de módulo. El objeto de código devuelve None
:
>>> dis.dis(compile('a + b', '<string>', 'exec'))
1 0 LOAD_NAME 0 (a)
3 LOAD_NAME 1 (b)
6 BINARY_ADD
7 POP_TOP <- discard result
8 LOAD_CONST 0 (None) <- load None on stack
11 RETURN_VALUE <- return top of stack
'single'
es una forma limitada de la 'exec'
cual acepta un código fuente que contiene una sola declaración (o varias declaraciones separadas por ;
) si la última declaración es una declaración de expresión, el código de bytes resultante también imprime repr
el valor de esa expresión en la salida estándar (!) .
Un if
- elif
- else
cadena, con un bucle else
, y try
con su except
, else
y finally
los bloques se considera una única instrucción.
Un fragmento de origen que contiene 2 declaraciones de nivel superior es un error para 'single'
, excepto en Python 2 que hay un error que a veces permite múltiples declaraciones de nivel superior en el código; solo se compila el primero; el resto se ignora:
En Python 2.7.8:
>>> exec(compile('a = 5\na = 6', '<string>', 'single'))
>>> a
5
Y en Python 3.4.2:
>>> exec(compile('a = 5\na = 6', '<string>', 'single'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
a = 5
^
SyntaxError: multiple statements found while compiling a single statement
Esto es muy útil para hacer shells interactivos de Python. Sin embargo, el valor de la expresión no se devuelve , incluso si eval
el código resultante.
Por lo tanto, la mayor distinción de exec
y en eval
realidad proviene de la compile
función y sus modos.
Además de compilar el código fuente en bytecode, compile
admite la compilación de árboles de sintaxis abstracta (analizar árboles de código Python) en code
objetos; y código fuente en árboles de sintaxis abstractos (el ast.parse
está escrito en Python y solo llama compile(source, filename, mode, PyCF_ONLY_AST)
); estos se utilizan, por ejemplo, para modificar el código fuente sobre la marcha, y también para la creación de código dinámico, ya que a menudo es más fácil manejar el código como un árbol de nodos en lugar de líneas de texto en casos complejos.
Si bien eval
solo le permite evaluar una cadena que contiene una sola expresión, puede hacer eval
una declaración completa, o incluso un módulo completo que ha sido compile
d en código de bytes; es decir, con Python 2, print
es una declaración y no se puede eval
dirigir directamente:
>>> eval('for i in range(3): print("Python is cool")')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print("Python is cool")
^
SyntaxError: invalid syntax
compile
con 'exec'
mode en un code
objeto y puedes eval
hacerlo ; la eval
función volverá None
.
>>> code = compile('for i in range(3): print("Python is cool")',
'foo.py', 'exec')
>>> eval(code)
Python is cool
Python is cool
Python is cool
Si uno mira a los eval
y exec
código fuente en CPython 3, esto es muy evidente; Ambos llaman PyEval_EvalCode
con los mismos argumentos, la única diferencia es que exec
regresa explícitamenteNone
.
Diferencias de sintaxis exec
entre Python 2 y Python 3
Una de las principales diferencias en Python 2 es que exec
es una declaración y eval
es una función integrada (ambas son funciones integradas en Python 3). Es un hecho bien conocido que la sintaxis oficial de exec
Python 2 es exec code [in globals[, locals]]
.
A diferencia de la mayoría de Python 2 a 3 portar guías parecen sugerir , la exec
declaración en CPython 2 puede ser utilizado también con la sintaxis que se ve exactamente como la exec
invocación de la función en Python 3. La razón es que Python 0.9.9 tuvieron la exec(code, globals, locals)
incorporada ¡en función! Y esa función incorporada fue reemplazada por una exec
declaración en algún lugar antes del lanzamiento de Python 1.0 .
Ya que era deseable para no romper la compatibilidad hacia atrás con Python 0.9.9, Guido van Rossum añadió un corte compatibilidad en 1993 : si el code
era una tupla de longitud 2 o 3, y globals
y locals
no se pasaron en la exec
declaración de otro modo, el code
sería interpretado como si el segundo y tercer elemento de la tupla fueran el globals
y locals
respectivamente. El truco de compatibilidad no se mencionó incluso en la documentación de Python 1.4 (la primera versión disponible en línea) ; y por lo tanto, muchos escritores no conocían las guías y herramientas de portabilidad, hasta que se volvió a documentar en noviembre de 2012 :
La primera expresión también puede ser una tupla de longitud 2 o 3. En este caso, las partes opcionales deben omitirse. El formulario exec(expr, globals)
es equivalente a exec expr in globals
, mientras que el formulario exec(expr, globals, locals)
es equivalente a exec expr in globals, locals
. La forma de tupla exec
proporciona compatibilidad con Python 3, donde exec
es una función en lugar de una declaración.
Sí, en CPython 2.7 que se conoce como una opción de compatibilidad con versiones anteriores (¿por qué confundir a las personas que hay una opción de compatibilidad con versiones anteriores?), Cuando en realidad había estado allí para la compatibilidad con versiones anteriores durante dos décadas .
Por lo tanto, while exec
es una declaración en Python 1 y Python 2, y una función incorporada en Python 3 y Python 0.9.9,
>>> exec("print(a)", globals(), {'a': 42})
42
ha tenido un comportamiento idéntico en posiblemente todas las versiones de Python ampliamente lanzadas; y funciona en Jython 2.5.2, PyPy 2.3.1 (Python 2.7.6) y IronPython 2.6.1 también (felicitaciones a ellos siguiendo de cerca el comportamiento indocumentado de CPython).
Lo que no puede hacer en Pythons 1.0 - 2.7 con su truco de compatibilidad es almacenar el valor de retorno de exec
en una variable:
Python 2.7.11+ (default, Apr 17 2016, 14:00:29)
[GCC 5.3.1 20160413] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = exec('print(42)')
File "<stdin>", line 1
a = exec('print(42)')
^
SyntaxError: invalid syntax
(que tampoco sería útil en Python 3, como exec
siempre regresa None
), o pasar una referencia a exec
:
>>> call_later(exec, 'print(42)', delay=1000)
File "<stdin>", line 1
call_later(exec, 'print(42)', delay=1000)
^
SyntaxError: invalid syntax
Qué patrón que alguien realmente podría haber usado, aunque poco probable;
O úsalo en una lista de comprensión:
>>> [exec(i) for i in ['print(42)', 'print(foo)']
File "<stdin>", line 1
[exec(i) for i in ['print(42)', 'print(foo)']
^
SyntaxError: invalid syntax
lo cual es abuso de las comprensiones de listas (¡use un for
bucle en su lugar!).
[i for i in globals().values() if hasattr(i, '__call__')][0]
una declaración o expresión? Si fue una expresión, ¿por qué no puedo usarlo@
como decorador?