Ответ 1
Короткий ответ, или TL; DR
В принципе, eval
используется для eval для одного динамически генерируемого выражения Python и exec
используется для exec динамически генерируемого кода Python только для его побочных эффектов.
eval
и exec
имеют следующие два отличия:
-
eval
принимает только одиночное выражение,exec
может принимать блок кода с инструкциями Python: циклы,try: except:
,class
и function/methoddef
переходы и т.д.Выражение в 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'
он компилирует одно выражение в байт-код, который возвращает значение этого выражения.
>>> 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 детали gory
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.
Если a 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
, оператор присваивания (aka 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'
режим ожидает одно выражение и будет генерировать байт-код, который, когда run вернет значение этого выражения:>>> 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'
, которая принимает исходный код, содержащий оператор single (или несколько операторов, разделенных символом;
), если последний оператор является выражением, полученный байт-код также выводитrepr
значения этого выражения на стандартный вывод (!).An
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-to-3 porting руководства показаться чтобы предложить, оператор 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
!).