Я дивився на динамічну оцінку коду Python, і натрапив на eval()
і compile()
функції, і exec
заяву.
Може хтось, будь ласка, пояснить різницю між eval
та exec
, і як compile()
вписуються різні режими ?
Я дивився на динамічну оцінку коду Python, і натрапив на eval()
і compile()
функції, і exec
заяву.
Може хтось, будь ласка, пояснить різницю між eval
та exec
, і як compile()
вписуються різні режими ?
Відповіді:
В основному, 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'
режим очікує єдиного виразу і видасть байт-код, який при запуску поверне значення цього виразу :
>>> 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
об’єкти; і вихідний код у абстрактні синтаксичні дерева (the 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
Якщо вивчити 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
цикл замість!).
42
це також вираз, і ви не можете використовувати його @
як декоратор.
decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE
; тобто ви не можете використовувати довільні вирази як декоратори, ТІЛЬКИ (можливо, пунктирним) ідентифікатором, за яким слід необов'язкові аргументи виклику.
a = b = c
це цілком коректне твердження, як і його права частина b = c
- що не є виразом.
exec
не є виразом: оператор у Python 2.x, а функція в Python 3.x. Він компілює та негайно оцінює твердження або набір оператора, що міститься у рядку. Приклад:
exec('print(5)') # prints 5.
# exec 'print 5' if you use Python 2.x, nor the exec neither the print is a function there
exec('print(5)\nprint(6)') # prints 5{newline}6.
exec('if True: print(6)') # prints 6.
exec('5') # does nothing and returns nothing.
eval
- це вбудована функція ( не твердження), яка оцінює вираз і повертає значення, яке вираз створює. Приклад:
x = eval('5') # x <- 5
x = eval('%d + 6' % x) # x <- 11
x = eval('abs(%d)' % -100) # x <- 100
x = eval('x = 5') # INVALID; assignment is not an expression.
x = eval('if 1: x = 4') # INVALID; if is a statement, not an expression.
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 - для вираження і повертає значення вираження.
вираз означає "щось", тоді як висловлювання означає "робити щось".
[i for i in globals().values() if hasattr(i, '__call__')][0]
заява чи вираз? Якщо це був вираз, чому я не можу використовувати його@
як декоратор?