La réponse courte, ou TL; DR
En gros, evalest utilisé pour eval Uate une seule expression Python généré dynamiquement, et execest utilisé pour exec ute code Python généré dynamiquement seulement pour ses effets secondaires.
evalet execont ces deux différences:
evalaccepte qu'une seule expression , execpeut prendre un bloc de code qui a des instructions Python: boucles, try: except:, classet 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 execignore 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 execses effets secondaires à l'intérieur de la fonction.
En Python 3, execest 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 compilein '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 evalfonction si une chaîne est passée), le compilelè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 codeobjet (qui contient le bytecode Python ) est passé à execou eval, ils se comportent de manière identique , à l'exception du fait qu'il execignore la valeur de retour, toujours en retournant Nonetoujours. Il est donc possible d'utiliser evalpour exécuter quelque chose qui a des instructions, si vous venez de le compiled 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 evalfonction si une chaîne est passée), le compilelè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 execfonction (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 evalfonction 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
execet les evaldeux acceptent que le programme / l'expression soit exécuté en tant que str, unicodeou bytesobjet contenant du code source, ou en tant codequ'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 evalse 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 Exprnœuds dans la grammaire abstraite Python ; l'inverse n'est pas vrai), vous pouvez toujours les utiliser execsi 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 evalretourne la valeur retournée par my_funcet la execrejette:
>>> 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, execn'accepte le code source qui contient des déclarations, comme def, for, while, importou 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 execet evalacceptent 2 arguments positionnels supplémentaires - globalset 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é execou eval, mais n'importe quel dictionnaire peut être utilisé pour globalset n'importe quel mappingpour locals(y compris dictbien 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 execcode 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 execet evalajoutez __builtins__automatiquement le module intégré aux globales s'il est manquant).
En Python 2, la syntaxe officielle de l' execinstruction 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 execou evalen compilant au codepréalable la source dans un objet. Le modeparamètre contrôle le type de fragment de code que la compilefonction 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 reprde la valeur de cette expression à la sortie standard (!) .
Une if- elif- elsechaîne, une boucle avec else, et tryavec son except, elseet des finallyblocs 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 evalle code résultant.
Ainsi la plus grande distinction execet evalvient en fait de la compilefonction et de ses modes.
En plus de compiler le code source en bytecode, compileprend en charge la compilation d'arbres de syntaxe abstraite (arbres d'analyse du code Python) en codeobjets; et le code source dans des arbres de syntaxe abstraite (le ast.parseest é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 evalque vous permet uniquement d'évaluer une chaîne qui contient une seule expression, vous pouvez evalune instruction entière, ou même un module entier qui a été compiled en bytecode; c'est-à-dire qu'avec Python 2, printc'est une déclaration et ne peut pas être evaldirigé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
compileavec le 'exec'mode dans un codeobjet et vous pouvez le eval faire ; la evalfonction 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 evalet execcode source dans CPython 3, c'est très évident; ils appellent tous les deux PyEval_EvalCodeavec les mêmes arguments, la seule différence étant qu'ils execretournent explicitementNone .
Différences de syntaxe execentre Python 2 et Python 3
L'une des principales différences dans Python 2 est qu'il execs'agit d'une instruction et d' evalune 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 execPython 2 est exec code [in globals[, locals]].
Contrairement à la majorité des Python 2 à 3 portage des guides semblent suggérer , la execdéclaration CPython 2 peut également être utilisé avec la syntaxe qui ressemble exactement comme l' execinvocation 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 execdé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, globalset localsn'était pas passé dans l' execinstruction autrement, le codeserait interprété comme si les 2e et 3e éléments du tuple étaient respectivement le globalset 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 execfournit la compatibilité avec Python 3, où se exectrouve 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 execest 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 execdans 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 exectoujours 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 forplutô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?