La réponse courte, ou TL; DR
En gros, eval
est utilisé pour eval Uate une seule expression Python généré dynamiquement, et exec
est utilisé pour exec ute code Python généré dynamiquement seulement pour ses effets secondaires.
eval
et exec
ont ces deux différences:
eval
accepte qu'une seule expression , exec
peut prendre un bloc de code qui a des instructions Python: boucles, try: except:
, class
et la fonction / méthodedef
initions de et ainsi de suite.
Une expression en Python est tout ce que vous pouvez avoir comme valeur dans une affectation de variable:
a_variable = (anything you can put within these parentheses is an expression)
eval
renvoie la valeur de l'expression donnée, alors qu'il exec
ignore la valeur de retour de son code, et renvoie toujours None
(en Python 2, c'est une instruction et ne peut pas être utilisée comme expression, donc elle ne retourne vraiment rien).
Dans les versions 1.0 - 2.7, exec
était une déclaration, car CPython avait besoin de produire un type d'objet de code différent pour les fonctions qui utilisaient exec
ses effets secondaires à l'intérieur de la fonction.
En Python 3, exec
est une fonction; son utilisation n'a aucun effet sur le bytecode compilé de la fonction où il est utilisé.
Donc en gros:
>>> 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
Le mode compile
in 'exec'
compile n'importe quel nombre d'instructions dans un bytecode qui renvoie implicitement toujours None
, tandis que dans le 'eval'
mode il compile une seule expression en bytecode qui retourne la valeur de cette expression.
>>> 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
Dans le 'eval'
mode (et donc avec la eval
fonction si une chaîne est passée), le compile
lève une exception si le code source contient des instructions ou autre chose au-delà d'une seule expression:
>>> 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 fait, l'instruction "eval n'accepte qu'une seule expression" s'applique uniquement lorsqu'une chaîne (qui contient le code source Python ) est passée à eval
. Ensuite, il est compilé en interne en bytecode en utilisant compile(source, '<string>', 'eval')
C'est de là que vient vraiment la différence.
Si un code
objet (qui contient le bytecode Python ) est passé à exec
ou eval
, ils se comportent de manière identique , à l'exception du fait qu'il exec
ignore la valeur de retour, toujours en retournant None
toujours. Il est donc possible d'utiliser eval
pour exécuter quelque chose qui a des instructions, si vous venez de le compile
d en bytecode avant au lieu de le passer comme une chaîne:
>>> eval(compile('if 1: print("Hello")', '<string>', 'exec'))
Hello
>>>
fonctionne sans problème, même si le code compilé contient des instructions. Il renvoie toujours None
, car il s'agit de la valeur de retour de l'objet de code renvoyé parcompile
.
Dans le 'eval'
mode (et donc avec la eval
fonction si une chaîne est passée), le compile
lève une exception si le code source contient des instructions ou autre chose au-delà d'une seule expression:
>>> 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 réponse plus longue, alias les détails sanglants
exec
et eval
La exec
fonction (qui était une instruction en Python 2 ) est utilisée pour exécuter une instruction ou un programme créé dynamiquement:
>>> program = '''
for i in range(3):
print("Python is cool")
'''
>>> exec(program)
Python is cool
Python is cool
Python is cool
>>>
La eval
fonction fait la même chose pour une expression unique , et renvoie la valeur de l'expression:
>>> a = 2
>>> my_calculation = '42 * a'
>>> result = eval(my_calculation)
>>> result
84
exec
et les eval
deux acceptent que le programme / l'expression soit exécuté en tant que str
, unicode
ou bytes
objet contenant du code source, ou en tant code
qu'objet contenant du bytecode Python.
Si un code source contenant str
/ unicode
/ a bytes
été transmis à exec
, il se comporte de manière équivalente à:
exec(compile(source, '<string>', 'exec'))
et eval
se comporte de manière similaire à:
eval(compile(source, '<string>', 'eval'))
Étant donné que toutes les expressions peuvent être utilisées comme des instructions en Python (celles-ci sont appelées les Expr
nœuds dans la grammaire abstraite Python ; l'inverse n'est pas vrai), vous pouvez toujours les utiliser exec
si vous n'avez pas besoin de la valeur de retour. C'est-à-dire que vous pouvez utiliser soit eval('my_func(42)')
ou exec('my_func(42)')
, la différence étant que eval
retourne la valeur retournée par my_func
et la exec
rejette:
>>> 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
>>>
Sur les 2, exec
n'accepte le code source qui contient des déclarations, comme def
, for
, while
, import
ou class
, l'instruction d'affectation (alias a = 42
), ou des programmes entiers:
>>> 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
Les deux exec
et eval
acceptent 2 arguments positionnels supplémentaires - globals
et locals
- qui sont les étendues de variables globales et locales que le code voit. Ces valeurs par défaut sont dans globals()
et locals()
dans la portée qui a appelé exec
ou eval
, mais n'importe quel dictionnaire peut être utilisé pour globals
et n'importe quel mapping
pour locals
(y compris dict
bien sûr). Ceux-ci peuvent être utilisés non seulement pour restreindre / modifier les variables que le code voit, mais sont également souvent utilisés pour capturer les variables que le exec
code utilisé crée:
>>> g = dict()
>>> l = dict()
>>> exec('global a; a, b = 123, 42', g, l)
>>> g['a']
123
>>> l
{'b': 42}
(Si vous affichez la valeur de l'ensemble g
, ce serait beaucoup plus long, car exec
et eval
ajoutez __builtins__
automatiquement le module intégré aux globales s'il est manquant).
En Python 2, la syntaxe officielle de l' exec
instruction est en fait exec code in globals, locals
, comme dans
>>> exec 'global a; a, b = 123, 42' in g, l
Cependant, la syntaxe alternative exec(code, globals, locals)
a toujours été acceptée aussi (voir ci-dessous).
compile
La fonction compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
intégrée peut être utilisée pour accélérer les invocations répétées du même code avec exec
ou eval
en compilant au code
préalable la source dans un objet. Le mode
paramètre contrôle le type de fragment de code que la compile
fonction accepte et le type de bytecode qu'elle produit. Les choix sont 'eval'
, 'exec'
et 'single'
:
'eval'
mode attend une seule expression et produira un bytecode qui, lors de l'exécution, retournera la valeur de cette expression :
>>> 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'
accepte tous les types de constructions python, des expressions simples aux modules entiers de code, et les exécute comme s'il s'agissait d'instructions de niveau supérieur de module. L'objet code renvoie 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'
est une forme limitée 'exec'
qui accepte un code source contenant une seule déclaration (ou plusieurs instructions séparées par ;
) si la dernière déclaration est une déclaration d'expression, le bytecode résultant également imprime la repr
de la valeur de cette expression à la sortie standard (!) .
Une if
- elif
- else
chaîne, une boucle avec else
, et try
avec son except
, else
et des finally
blocs est considéré comme une seule instruction.
Un fragment source contenant 2 instructions de niveau supérieur est une erreur pour le 'single'
, sauf qu'en Python 2 il y a un bogue qui autorise parfois plusieurs instructions de haut niveau dans le code; seul le premier est compilé; les autres sont ignorés:
En Python 2.7.8:
>>> exec(compile('a = 5\na = 6', '<string>', 'single'))
>>> a
5
Et 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
Ceci est très utile pour créer des shells Python interactifs. Cependant, la valeur de l'expression n'est pas retournée , même si vous eval
le code résultant.
Ainsi la plus grande distinction exec
et eval
vient en fait de la compile
fonction et de ses modes.
En plus de compiler le code source en bytecode, compile
prend en charge la compilation d'arbres de syntaxe abstraite (arbres d'analyse du code Python) en code
objets; et le code source dans des arbres de syntaxe abstraite (le ast.parse
est écrit en Python et juste des appels compile(source, filename, mode, PyCF_ONLY_AST)
); ceux-ci sont utilisés par exemple pour modifier le code source à la volée, et également pour la création de code dynamique, car il est souvent plus facile de gérer le code comme un arbre de nœuds au lieu de lignes de texte dans des cas complexes.
Alors eval
que vous permet uniquement d'évaluer une chaîne qui contient une seule expression, vous pouvez eval
une instruction entière, ou même un module entier qui a été compile
d en bytecode; c'est-à-dire qu'avec Python 2, print
c'est une déclaration et ne peut pas être eval
dirigée directement:
>>> 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
avec le 'exec'
mode dans un code
objet et vous pouvez le eval
faire ; la eval
fonction reviendra 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 l'on regarde eval
et exec
code source dans CPython 3, c'est très évident; ils appellent tous les deux PyEval_EvalCode
avec les mêmes arguments, la seule différence étant qu'ils exec
retournent explicitementNone
.
Différences de syntaxe exec
entre Python 2 et Python 3
L'une des principales différences dans Python 2 est qu'il exec
s'agit d'une instruction et d' eval
une fonction intégrée (les deux sont des fonctions intégrées dans Python 3). C'est un fait bien connu que la syntaxe officielle de exec
Python 2 est exec code [in globals[, locals]]
.
Contrairement à la majorité des Python 2 à 3 portage des guides semblent suggérer , la exec
déclaration CPython 2 peut également être utilisé avec la syntaxe qui ressemble exactement comme l' exec
invocation de fonction en Python 3. La raison en est que Python 0.9.9 avait l' exec(code, globals, locals)
intégré en fonction! Et cette fonction intégrée a été remplacée par une exec
déclaration quelque part avant la sortie de Python 1.0 .
Puisqu'il était souhaitable de ne pas rompre la rétrocompatibilité avec Python 0.9.9, Guido van Rossum a ajouté un hack de compatibilité en 1993 : si le code
était un tuple de longueur 2 ou 3, globals
et locals
n'était pas passé dans l' exec
instruction autrement, le code
serait interprété comme si les 2e et 3e éléments du tuple étaient respectivement le globals
et locals
. Le piratage de compatibilité n'était pas mentionné même dans la documentation Python 1.4 (la première version disponible en ligne) ; et donc n'était pas connu de nombreux auteurs des guides et outils de portage, jusqu'à ce qu'il soit à nouveau documenté en novembre 2012 :
La première expression peut également être un tuple de longueur 2 ou 3. Dans ce cas, les parties facultatives doivent être omises. Le formulaire exec(expr, globals)
est équivalent à exec expr in globals
, tandis que le formulaire exec(expr, globals, locals)
est équivalent à exec expr in globals, locals
. La forme tuple de exec
fournit la compatibilité avec Python 3, où se exec
trouve une fonction plutôt qu'une instruction.
Oui, dans CPython 2.7, elle est désignée comme une option de compatibilité descendante (pourquoi confondre les gens avec le fait qu'il existe une option de compatibilité descendante), alors qu'elle était en fait là pour la compatibilité descendante depuis deux décennies .
Ainsi, while exec
est une instruction en Python 1 et Python 2, et une fonction intégrée dans Python 3 et Python 0.9.9,
>>> exec("print(a)", globals(), {'a': 42})
42
a eu un comportement identique dans toutes les versions Python largement diffusées; et fonctionne également dans Jython 2.5.2, PyPy 2.3.1 (Python 2.7.6) et IronPython 2.6.1 (bravo à eux en suivant de près le comportement non documenté de CPython).
Ce que vous ne pouvez pas faire dans Pythons 1.0 - 2.7 avec son hack de compatibilité, c'est de stocker la valeur de retour de exec
dans une 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
(qui ne serait pas utile non plus dans Python 3, comme exec
toujours retourne None
), ou passez une référence à exec
:
>>> call_later(exec, 'print(42)', delay=1000)
File "<stdin>", line 1
call_later(exec, 'print(42)', delay=1000)
^
SyntaxError: invalid syntax
Quel modèle que quelqu'un aurait pu utiliser, quoique peu probable;
Ou utilisez-le dans une liste de compréhension:
>>> [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
ce qui est un abus de compréhension de liste (utilisez for
plutôt une boucle!).
[i for i in globals().values() if hasattr(i, '__call__')][0]
une déclaration ou une expression? Si c'était une expression, pourquoi ne puis-je pas l'utiliser avec@
comme décorateur?