Краткий ответ, или TL; DR
В основном eval
используется для eval использования одного динамически генерируемого выражения Python, а exec
используется для exec использовать динамически генерируемый код Python только для его побочных эффектов.
eval
и exec
имеют следующие два различия:
eval
принимает только одно одиночное выражение , exec
может принимать блок кода, содержащий операторы Python: циклы, try: except:
, class
и функцию / метод def
инициативы и так далее.
Выражение в Python - это то, что вы можете использовать в качестве значения в присваивании переменной:
a_variable = (anything you can put within these parentheses is an expression)
eval
возвращает значение данного выражения, тогда как exec
игнорирует возвращаемое значение из своего кода и всегда возвращает None
(в Python 2 это оператор и не может использоваться как выражение, поэтому оно действительно ничего не возвращает).
В версиях 1.0 - 2.7, exec
был оператором, потому что CPython необходимо было создать объект кода другого типа для функций, которые использовали exec
для своих побочных эффектов внутри функции.
В Python 3 exec
является функцией; его использование не влияет на скомпилированный байт-код функции, в которой он используется.
Таким образом, в основном:
>>> 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
Режим compile
в 'exec'
компилирует любое количество операторов в байт-код, который неявно всегда возвращает None
, тогда как в режиме 'eval'
он компилирует выражение single в байт-код, который возвращает значение этого выражения.
>>> 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
В режиме 'eval'
(и, следовательно, с функцией eval
, если передается строка), compile
вызывает исключение, если исходный код содержит операторы или что-то еще, кроме одного выражения:
>>> 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
На самом деле оператор "eval принимает только одно выражение" применяется только тогда, когда строка (которая содержит Python исходный код ) передана в eval
. Затем он внутренне компилируется в байт-код с использованием compile(source, '<string>', 'eval')
. Именно в этом и заключается разница.
Если объект code
(содержащий Python байт-код ) передается exec
или eval
, , они ведут себя одинаково , за исключением того факта, что exec
игнорирует возвращаемое значение, по-прежнему возвращая None
всегда. Таким образом, можно использовать eval
для выполнения чего-то, имеющего операторы, если вы просто compile
d передали это в байт-код, вместо того, чтобы передавать это как строку:
>>> eval(compile('if 1: print("Hello")', '<string>', 'exec'))
Hello
>>>
работает без проблем, хотя скомпилированный код содержит операторы. Он по-прежнему возвращает None
, поскольку это возвращаемое значение объекта кода, возвращенного из compile
.
В режиме 'eval'
(и, следовательно, с помощью функции eval
, если передается строка), compile
вызывает исключение, если исходный код содержит операторы или что-либо еще, кроме одного выражения:
>>> 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
Более длинный ответ, a.k.a кровавые подробности
exec
и eval
Функция exec
(которая была оператором в Python 2 ) используется для выполнения динамически созданного оператора или программы:
>>> program = '''
for i in range(3):
print("Python is cool")
'''
>>> exec(program)
Python is cool
Python is cool
Python is cool
>>>
Функция eval
делает то же самое для одиночного выражения , и возвращает значение выражения:
>>> a = 2
>>> my_calculation = '42 * a'
>>> result = eval(my_calculation)
>>> result
84
exec
и eval
оба принимают программу / выражение для запуска либо как str
, unicode
или bytes
объект, содержащий исходный код, либо как code
объект который содержит байт-код Python.
Если str
/ unicode
/ bytes
, содержащий исходный код, был передан exec
, он ведет себя эквивалентно:
exec(compile(source, '<string>', 'exec'))
и eval
аналогично ведут себя эквивалентно:
eval(compile(source, '<string>', 'eval'))
Поскольку все выражения можно использовать в качестве операторов в Python (они называются Expr
узлами в абстрактной грамматике Python ; обратное неверно), вы всегда можете использовать exec
, если вы не нужно возвращаемое значение. То есть вы можете использовать либо eval('my_func(42)')
, либо exec('my_func(42)')
, с той разницей, что eval
возвращает значение, возвращаемое my_func
, а exec
отбрасывает его:
>>> 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
>>>
Из 2 только exec
принимает исходный код, содержащий операторы, такие как def
, for
, while
, import
или class
, оператор присваивания (он же a = 42
), или целые программы:
>>> 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
И exec
, и eval
принимают 2 дополнительных позиционных аргумента - globals
и locals
- которые являются областями глобальных и локальных переменных, которые видит код. По умолчанию это globals()
и locals()
в области, которая называется exec
или eval
, но любой словарь может использоваться для globals
и любой mapping
для locals
(включая, конечно, dict
). Они могут использоваться не только для ограничения / изменения переменных, которые видит код, но также часто используются для захвата переменных, которые создает код exec
:
>>> g = dict()
>>> l = dict()
>>> exec('global a; a, b = 123, 42', g, l)
>>> g['a']
123
>>> l
{'b': 42}
(Если вы отобразите значение всего g
, оно будет намного длиннее, потому что exec
и eval
добавляют встроенный модуль как __builtins__
к глобальным переменным автоматически, если он отсутствует).
В Python 2 официальный синтаксис для оператора exec
на самом деле exec code in globals, locals
, как в
>>> exec 'global a; a, b = 123, 42' in g, l
Однако альтернативный синтаксис exec(code, globals, locals)
также всегда принимался (см. Ниже).
compile
Встроенный compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
может быть использован для ускорения повторных вызовов одного и того же кода с exec
или eval
путем предварительной компиляции источника в объект code
. Параметр mode
управляет видом фрагмента кода, который принимает функция compile
, и типом байт-кода, который она создает. Возможны варианты 'eval'
, 'exec'
и 'single'
:
'eval'
режим ожидает одно выражение и будет генерировать байт-код, который при запуске вернет значение этого выражения :
>>> 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'
принимает любые типы конструкций python от отдельных выражений до целых модулей кода и выполняет их, как если бы они были операторами верхнего уровня модуля. Кодовый объект возвращает 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'
- это ограниченная форма 'exec'
, которая принимает исходный код, содержащий один оператор (или несколько операторов, разделенных ;
), если последний оператор является оператором выражения результирующий байт-код также выводит repr
значения этого выражения на стандартный вывод (!) .
Цепочка if
- elif
- else
, цикл с else
и try
с блоками except
, else
и finally
считаются одним оператором.
Исходный фрагмент, содержащий 2 оператора верхнего уровня, является ошибкой для 'single'
, за исключением того, что в Python 2 есть ошибка , которая иногда допускает несколько операторов верхнего уровня в коде; компилируется только первое; остальные игнорируются:
В Python 2.7.8:
>>> exec(compile('a = 5\na = 6', '<string>', 'single'))
>>> a
5
А в 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
Это очень полезно для создания интерактивных оболочек Python. Однако значение выражения не возвращается , даже если вы eval
получившийся код.
Таким образом, наибольшее различие exec
и eval
на самом деле происходит от функции compile
и ее режимов.
Помимо компиляции исходного кода в байт-код, compile
поддерживает компиляцию абстрактных синтаксических деревьев (синтаксический анализ деревьев кода Python) в code
объектах; и исходный код в абстрактные синтаксические деревья (ast.parse
написан на Python и просто вызывает compile(source, filename, mode, PyCF_ONLY_AST)
); они используются, например, для изменения исходного кода на лету, а также для динамического создания кода, поскольку в сложных случаях часто проще обрабатывать код как дерево узлов, а не строк текста.
Хотя eval
позволяет вам вычислять только строку, содержащую одно выражение, вы можете eval
весь оператор или даже целый модуль, который был compile
d, преобразован в байт-код; то есть, в Python 2 print
является оператором, и его нельзя eval
приводить напрямую:
>>> 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
с режимом 'exec'
в объект code
, и вы можете eval
it ; функция eval
вернет 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
Если посмотреть на eval
и exec
исходный код в CPython 3, это очень очевидно; они оба вызывают PyEval_EvalCode
с одинаковыми аргументами, с той лишь разницей, что exec
явно возвращает None
.
Синтаксические различия exec
между Python 2 и Python 3
Одним из основных отличий в Python 2 является то, что exec
является оператором, а eval
является встроенной функцией (обе являются встроенными функциями в Python 3).
Общеизвестно, что официальный синтаксис exec
в Python 2 - exec code [in globals[, locals]]
.
В отличие от большинства портов Python 2-к-3 направляющих кажутся предполагающими , оператор exec
в CPython 2 также можно использовать с синтаксисом, который выглядит точно как вызов функции exec
в Python 3. Причина в том, что Python 0.9.9 имеет встроенную функцию exec(code, globals, locals)
! И эта встроенная функция была заменена на exec
оператор где-то перед выпуском Python 1.0 .
Поскольку было желательно не нарушать обратную совместимость с Python 0.9.9, Гвидо ван Россум добавил хак совместимости в 1993 : если code
был кортежом длины 2 или 3, и globals
и locals
не были переданы в оператор exec
, иначе code
будет интерпретироваться так, как если бы 2-й и 3-й элементы кортежа были globals
и locals
соответственно. Хакерская совместимость не упоминалась даже в документации Python 1.4 (самая ранняя доступная онлайн версия) ; и, таким образом, не было известно многим авторам руководств по портированию и инструментов, пока не было задокументировано снова в ноябре 2012 :
Первое выражение также может быть кортежем длины 2 или 3. В этом случае необязательные части должны быть опущены. Форма exec(expr, globals)
эквивалентна exec expr in globals
, а форма exec(expr, globals, locals)
эквивалентна exec expr in globals, locals
. Форма кортежа exec
обеспечивает совместимость с Python 3, где exec
является функцией, а не оператором.
Да, в CPython 2.7 это удобно называть опцией прямой совместимости (зачем путать людей с тем, что вообще существует опция обратной совместимости),
когда он действительно был там для обратной совместимости в течение двух десятилетий .
Таким образом, хотя exec
является оператором в Python 1 и Python 2, а также встроенной функцией в Python 3 и Python 0.9.9,
>>> exec("print(a)", globals(), {'a': 42})
42
имел идентичное поведение, возможно, во всех широко выпущенных версиях Python; и работает в Jython 2.5.2, PyPy 2.3.1 (Python 2.7.6) и IronPython 2.6.1 (спасибо им за недокументированное поведение CPython).
То, что вы не можете сделать в Pythons 1.0 - 2.7 с его хаком совместимости, - это сохранить возвращаемое значение exec
в переменной:
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
(что было бы бесполезно в Python 3, так как exec
всегда возвращает None
), или передайте ссылку на exec
:
>>> call_later(exec, 'print(42)', delay=1000)
File "<stdin>", line 1
call_later(exec, 'print(42)', delay=1000)
^
SyntaxError: invalid syntax
Какой паттерн может использовать кто-то, хотя и маловероятный;
Или используйте его для понимания списка:
>>> [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
- злоупотребление пониманием списка (вместо этого используйте цикл for
!).