Я смотрел на динамической оценке кода Python, и попадался eval()
и compile()
функции, а также exec
утверждение.
Может кто-нибудь объяснить, пожалуйста, разницу между eval
и exec
, и как различные способы compile()
вписываются?
В основном, eval
используются для Eval хать один динамически выражение Python, и 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
in '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
передали это в байт-код, вместо того, чтобы передавать это как строку:
>>> 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
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'
mode ожидает одно выражение и выдаст байт-код, который при запуске вернет значение этого выражения :
>>> 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
преобразован в байт-код; то есть, с 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
это ; 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
Если посмотреть на исходный код CPython 3 eval
и его exec
исходный код, это очень очевидно; они оба вызывают 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 его удобно называть опцией прямой совместимости (зачем путать людей с тем, что вообще существует опция обратной совместимости), когда он фактически существовал для обратной совместимости в течение двух десятилетий .
Таким образом, while 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
вместо этого цикл!).
[i for i in globals().values() if hasattr(i, '__call__')][0]
ли заявление или выражение? Если это было выражение, почему я не могу использовать его в@
качестве декоратора?42
также является выражением, и вы не можете использовать его@
в качестве декоратора.decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE
: то есть вы не можете использовать произвольные выражения в качестве декораторов, ТОЛЬКО (возможно, пунктирный) идентификатор, за которым следуют необязательные аргументы вызова.a = b = c
это совершенно допустимое утверждение, как и его правая часть,b = c
которое не является выражением.exec
не является выражением: оператор в Python 2.x и функция в Python 3.x. Он компилирует и сразу оценивает оператор или набор операторов, содержащихся в строке. Пример:eval
является встроенной функцией ( не оператором), которая оценивает выражение и возвращает значение, которое производит выражение. Пример:compile
это версия нижнего уровняexec
иeval
. Он не выполняет и не оценивает ваши операторы или выражения, но возвращает объект кода, который может это сделать. Режимы следующие:compile(string, '', 'eval')
возвращает объект кода, который был бы выполнен, если бы вы сделалиeval(string)
. Обратите внимание, что вы не можете использовать операторы в этом режиме; допустимо только (одно) выражение.compile(string, '', 'exec')
возвращает объект кода, который был бы выполнен, если бы вы сделалиexec(string)
. Вы можете использовать любое количество утверждений здесь.compile(string, '', 'single')
Это какexec
режим, но он будет игнорировать все, кроме первого утверждения. Обратите внимание, что операторif
/else
с его результатами считается одним оператором.источник
exec()
теперь это фактически функция.exec
это утверждение в версии, на которую вы нацеливались, обманчиво включать эти символы, и, если вы попытаетесь использоватьin globals, locals
, также ошибка.exec
поддерживает круглые скобки и работает как вызов в Python 2 .x = (y)
, что может быть правдой. Другой оператор, превращенный в функцию, являетсяprint
; сравнить результатprint(1, 2, 3)
в Python 2 и 3.exec для утверждения и ничего не возвращает. eval для выражения и возвращает значение выражения.
выражение означает «что-то», а выражение означает «сделать что-то».
источник