eval、exec 和 compile 之间有什么区别? [英] What's the difference between eval, exec, and compile?
问题描述
我一直在研究 Python 代码的动态评估,并遇到了 eval()
和 compile()
函数,以及 exec代码> 语句.
谁能解释一下eval
和exec
之间的区别,以及compile()
的不同模式如何适应?
简短的回答,或 TL;DR
基本上,使用eval
求值评估单个动态生成的 Python 表达式,以及exec
用于execute 动态生成的 Python 代码只是为了它的副作用.
eval
和 exec
有这两个区别:
eval
只接受一个单个表达式,exec
可以接受一个包含 Python 语句的代码块:loops、尝试:except:
、class
和函数/方法def
initions 等等.Python 中的表达式是您可以在变量赋值中使用的任何值:
a_variable =(你可以放在这些括号内的任何东西都是一个表达式)
eval
返回给定表达式的值,而exec
忽略其代码的返回值,并且总是返回None
(在 Python 2 中它是一个语句,不能用作表达式,所以它真的不返回任何东西).
在 1.0 - 2.7 版本中,exec
是一个语句,因为 CPython 需要为使用 exec
在内部产生副作用的函数生成一种不同类型的代码对象.功能.
在 Python 3 中,exec
是一个函数;它的使用对使用它的函数的编译字节码没有影响.
因此基本上:
<预><代码>>>>一 = 5>>>eval('37 + a') # 是一个表达式42>>>exec('37 + a') # 是一个表达式语句;值被忽略(无返回)>>>exec('a = 47') # 修改一个全局变量作为副作用>>>一种47>>>eval('a = 47') # 你不能评估一个语句回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中文件<小时>
'exec'
模式下的 compile
将任意数量的语句编译成一个字节码,该字节码总是隐式返回 None
,而在 'eval'
模式将单个表达式编译成字节码,返回该表达式的值.
在 'eval'
模式下(如果传入一个字符串,则使用 eval
函数),compile
会引发异常如果源代码包含语句或除单个表达式之外的任何其他内容:
<小时>
实际上,语句eval 只接受单个表达式" 仅适用于将字符串(包含 Python 源代码)传递给 eval
.然后使用 compile(source, '<string>', 'eval')
这就是差异的真正来源.
如果一个 code
对象(包含 Python bytecode)被传递给 exec
或 eval
,它们的行为相同,除了exec
忽略返回值,仍然总是返回None
.所以可以使用 eval
来执行一些有语句的东西,如果你只是 compile
之前将它编译成字节码而不是将它作为字符串传递:
工作没有问题,即使编译后的代码包含语句.它仍然返回None
,因为那是compile
返回的代码对象的返回值.
在 'eval'
模式下(如果传入一个字符串,则使用 eval
函数),compile
会引发异常如果源代码包含语句或除单个表达式之外的任何其他内容:
更长的答案,也就是血腥的细节
exec
和 eval
exec
函数(其中Python 2 中的语句) 用于执行动态创建的语句或程序:
exec
和 eval
都接受要作为 str
、unicode
或bytes
包含源代码的对象,或者作为包含 Python 字节码的 code
对象.
如果将包含源代码的 str
/unicode
/bytes
传递给 exec
,则其行为等效于:
exec(compile(source, '', 'exec'))
和 eval
类似地等效于:
eval(compile(source, '', 'eval'))
<小时>
由于所有表达式都可以用作 Python 中的语句(这些在 Python 中称为 Expr
节点 抽象语法;反之则不然),如果不需要返回值,可以随时使用 exec
.也就是说,您可以使用 eval('my_func(42)')
或 exec('my_func(42)')
,区别在于 eval
返回my_func
返回的值,exec
丢弃它:
在这 2 个中,只有 exec
接受包含语句的源代码,例如 def
、for
、while
、import
或 class
、赋值语句(又名 a = 42
)或整个程序:
<小时>
exec
和 eval
都接受 2 个额外的位置参数 - globals
和 locals
- 它们是全局和代码看到的局部变量范围.这些默认为调用 exec
或 eval
的范围内的 globals()
和 locals()
,但任何字典可用于 globals
和任何 mapping
用于 locals
(当然包括 dict
).这些不仅可以用于限制/修改代码看到的变量,而且通常还用于捕获exec
代码创建的变量:
(如果你显示整个g
的值,会更长,因为exec
和eval
添加了内置函数模块作为 __builtins__
自动添加到全局变量(如果缺少).
在Python 2中,exec
语句的官方语法实际上是exec code in globals, locals
,如
然而,替代语法 exec(code, globals, locals)
也一直被接受(见下文).
编译
compile(source, filename, mode, flags=0,dont_inherit=False, optimize=-1)
内置可用于加快重复调用相同代码的 exec
或 eval
通过事先将源代码编译为 code
对象.mode
参数控制 compile
函数接受的代码片段的种类和它产生的字节码的种类.选项为 'eval'
、'exec'
和 'single'
:
<预><代码>>>>dis.dis(compile('a + b', ''eval'
模式需要一个单一的表达式,并且会产生字节码,运行时将返回那个表达式的值:', 'eval'))1 0 LOAD_NAME 0 (a)3 LOAD_NAME 1 (b)6 BINARY_ADD7 RETURN_VALUE
<预><代码>>>>dis.dis(compile('a + b', ''exec'
接受从单个表达式到整个代码模块的任何类型的 Python 构造,并像执行模块顶级语句一样执行它们.代码对象返回None
:', 'exec'))1 0 LOAD_NAME 0 (a)3 LOAD_NAME 1 (b)6 BINARY_ADD7 POP_TOP <- 丢弃结果8 LOAD_CONST 0 (None) <- 在堆栈上加载 None11 RETURN_VALUE <- 返回栈顶 'single'
是'exec'
的一种有限形式,它接受包含一个 single 语句(或多个由;
分隔的语句)如果最后一个语句是表达式语句,则生成的字节码也会将该表达式的值的repr
打印到标准输出(!).一个
if
-elif
-else
链,一个带有else
的循环,以及try
及其except
、else
和finally
块被视为单个语句.包含 2 个顶级语句的源代码片段对于
'single'
来说是一个错误,除了在 Python 2 中存在一个错误有时允许多个顶级语句在编码;只编译第一个;其余的被忽略:在 Python 2.7.8 中:
<预><代码>>>>exec(compile('a = 5 a = 6', '', 'single'))>>>一种5 在 Python 3.4.2 中:
<预><代码>>>>exec(compile('a = 5 a = 6', '', 'single'))回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中文件 ",第 1 行一 = 5^SyntaxError:编译单个语句时发现多个语句 这对于制作交互式 Python shell 非常有用.但是,表达式的值不会返回,即使您
eval
结果代码.
因此 exec
和 eval
的最大区别实际上来自于 compile
函数及其模式.
除了将源代码编译为字节码之外,compile
还支持编译 抽象语法树(Python代码的解析树)为code
对象;并将源代码转换为抽象语法树(ast.parse
是用 Python 编写的,只需调用 compile(source, filename, mode, PyCF_ONLY_AST)
);例如,这些用于动态修改源代码,也用于动态代码创建,因为在复杂情况下,将代码作为节点树而不是文本行处理通常更容易.
虽然 eval
只允许你计算一个包含单个表达式的字符串,但你可以eval
整个语句,甚至是一个已经 的整个模块将
d 编译成字节码;也就是说,在 Python 2 中,print
是一个语句,不能被 eval
直接引导:
compile
用 'exec'
模式将它编译成 code
对象,你可以 eval
它;eval
函数将返回 None
.
如果查看 eval
和 exec
CPython 3 中的源代码,这一点很明显;他们都用相同的参数调用 PyEval_EvalCode
,唯一的区别是 exec
显式返回 None
.
Python 2 和 Python 3 之间 exec
的语法差异
Python 2 的主要区别之一是 exec
是一个语句,而 eval
是一个内置函数(两者都是内置的)Python 3 中的 -in 函数).众所周知,Python 2中exec
的官方语法是exec code [in globals[, locals]]
.
不同于大多数 Python 2-to-3 移植 指南 似乎 建议,CPython 2 中的 exec
语句也可以与 看起来 完全 像 exec
的语法一起使用> Python 3 中的函数调用.原因是 Python 0.9.9 有 exec(code, globals, locals)
内置函数!并且该内置函数被替换为 exec
语句 在 Python 1.0 发布之前的某个地方.
由于希望不破坏与 Python 0.9.9 的向后兼容性,Guido van Rossum 在 1993 年添加了一个兼容性黑客:如果 code
是长度为 2 或 3 的元组,并且 globals
和 locals
没有传递到 exec
语句,否则 code
将被解释为好像元组的第二个和第三个元素是 globals
和 locals
分别.即使在 Python 1.4 文档(最早可用的在线版本)中也没有提到兼容性黑客);因此,许多移植指南和工具的作者并不知道,直到它成为 记录 再次于 2012 年 11 月:
第一个表达式也可能是长度为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 中是一个内置函数,
可能在每个广泛发布的 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+(默认,2016 年 4 月 17 日,14:00:29)[GCC 5.3.1 20160413] 在 linux2 上输入帮助"、版权"、信用"或许可证"以获取更多信息.>>>a = exec('打印(42)')文件",第 1 行a = exec('打印(42)')^语法错误:无效语法
(这在 Python 3 中也没有用,因为 exec
总是返回 None
),或者传递对 exec
的引用:
某人可能实际使用过的模式,尽管不太可能;
或者在列表推导中使用它:
<预><代码>>>>[exec(i) for i in ['print(42)', 'print(foo)']文件这是对列表推导式的滥用(改用 for
循环!).
I've been looking at dynamic evaluation of Python code, and come across the eval()
and compile()
functions, and the exec
statement.
Can someone please explain the difference between eval
and exec
, and how the different modes of compile()
fit in?
The short answer, or TL;DR
Basically, eval
is used to evaluate a single dynamically generated Python expression, and exec
is used to execute dynamically generated Python code only for its side effects.
eval
and exec
have these two differences:
eval
accepts only a single expression,exec
can take a code block that has Python statements: loops,try: except:
,class
and function/methoddef
initions and so on.An expression in Python is whatever you can have as the value in a variable assignment:
a_variable = (anything you can put within these parentheses is an expression)
eval
returns the value of the given expression, whereasexec
ignores the return value from its code, and always returnsNone
(in Python 2 it is a statement and cannot be used as an expression, so it really does not return anything).
In versions 1.0 - 2.7, exec
was a statement, because CPython needed to produce a different kind of code object for functions that used exec
for its side effects inside the function.
In Python 3, exec
is a function; its use has no effect on the compiled bytecode of the function where it is used.
Thus basically:
>>> 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
The compile
in 'exec'
mode compiles any number of statements into a bytecode that implicitly always returns None
, whereas in 'eval'
mode it compiles a single expression into bytecode that returns the value of that 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
In the 'eval'
mode (and thus with the eval
function if a string is passed in), the compile
raises an exception if the source code contains statements or anything else beyond a single 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
Actually the statement "eval accepts only a single expression" applies only when a string (which contains Python source code) is passed to eval
. Then it is internally compiled to bytecode using compile(source, '<string>', 'eval')
This is where the difference really comes from.
If a code
object (which contains Python bytecode) is passed to exec
or eval
, they behave identically, excepting for the fact that exec
ignores the return value, still returning None
always. So it is possible use eval
to execute something that has statements, if you just compile
d it into bytecode before instead of passing it as a string:
>>> eval(compile('if 1: print("Hello")', '<string>', 'exec'))
Hello
>>>
works without problems, even though the compiled code contains statements. It still returns None
, because that is the return value of the code object returned from compile
.
In the 'eval'
mode (and thus with the eval
function if a string is passed in), the compile
raises an exception if the source code contains statements or anything else beyond a single 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
The longer answer, a.k.a the gory details
exec
and eval
The exec
function (which was a statement in Python 2) is used for executing a dynamically created statement or program:
>>> program = '''
for i in range(3):
print("Python is cool")
'''
>>> exec(program)
Python is cool
Python is cool
Python is cool
>>>
The eval
function does the same for a single expression, and returns the value of the expression:
>>> a = 2
>>> my_calculation = '42 * a'
>>> result = eval(my_calculation)
>>> result
84
exec
and eval
both accept the program/expression to be run either as a str
, unicode
or bytes
object containing source code, or as a code
object which contains Python bytecode.
If a str
/unicode
/bytes
containing source code was passed to exec
, it behaves equivalently to:
exec(compile(source, '<string>', 'exec'))
and eval
similarly behaves equivalent to:
eval(compile(source, '<string>', 'eval'))
Since all expressions can be used as statements in Python (these are called the Expr
nodes in the Python abstract grammar; the opposite is not true), you can always use exec
if you do not need the return value. That is to say, you can use either eval('my_func(42)')
or exec('my_func(42)')
, the difference being that eval
returns the value returned by my_func
, and exec
discards it:
>>> 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
>>>
Of the 2, only exec
accepts source code that contains statements, like def
, for
, while
, import
, or class
, the assignment statement (a.k.a a = 42
), or entire programs:
>>> 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
Both exec
and eval
accept 2 additional positional arguments - globals
and locals
- which are the global and local variable scopes that the code sees. These default to the globals()
and locals()
within the scope that called exec
or eval
, but any dictionary can be used for globals
and any mapping
for locals
(including dict
of course). These can be used not only to restrict/modify the variables that the code sees, but are often also used for capturing the variables that the exec
uted code creates:
>>> g = dict()
>>> l = dict()
>>> exec('global a; a, b = 123, 42', g, l)
>>> g['a']
123
>>> l
{'b': 42}
(If you display the value of the entire g
, it would be much longer, because exec
and eval
add the built-ins module as __builtins__
to the globals automatically if it is missing).
In Python 2, the official syntax for the exec
statement is actually exec code in globals, locals
, as in
>>> exec 'global a; a, b = 123, 42' in g, l
However the alternate syntax exec(code, globals, locals)
has always been accepted too (see below).
compile
The compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
built-in can be used to speed up repeated invocations of the same code with exec
or eval
by compiling the source into a code
object beforehand. The mode
parameter controls the kind of code fragment the compile
function accepts and the kind of bytecode it produces. The choices are 'eval'
, 'exec'
and 'single'
:
'eval'
mode expects a single expression, and will produce bytecode that when run will return the value of that 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'
accepts any kinds of python constructs from single expressions to whole modules of code, and executes them as if they were module top-level statements. The code object returnsNone
:>>> 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'
is a limited form of'exec'
which accepts a source code containing a single statement (or multiple statements separated by;
) if the last statement is an expression statement, the resulting bytecode also prints therepr
of the value of that expression to the standard output(!).An
if
-elif
-else
chain, a loop withelse
, andtry
with itsexcept
,else
andfinally
blocks is considered a single statement.A source fragment containing 2 top-level statements is an error for the
'single'
, except in Python 2 there is a bug that sometimes allows multiple toplevel statements in the code; only the first is compiled; the rest are ignored:In Python 2.7.8:
>>> exec(compile('a = 5 a = 6', '<string>', 'single')) >>> a 5
And in Python 3.4.2:
>>> exec(compile('a = 5 a = 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
This is very useful for making interactive Python shells. However, the value of the expression is not returned, even if you
eval
the resulting code.
Thus greatest distinction of exec
and eval
actually comes from the compile
function and its modes.
In addition to compiling source code to bytecode, compile
supports compiling abstract syntax trees (parse trees of Python code) into code
objects; and source code into abstract syntax trees (the ast.parse
is written in Python and just calls compile(source, filename, mode, PyCF_ONLY_AST)
); these are used for example for modifying source code on the fly, and also for dynamic code creation, as it is often easier to handle the code as a tree of nodes instead of lines of text in complex cases.
While eval
only allows you to evaluate a string that contains a single expression, you can eval
a whole statement, or even a whole module that has been compile
d into bytecode; that is, with Python 2, print
is a statement, and cannot be eval
led directly:
>>> 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
it with 'exec'
mode into a code
object and you can eval
it; the eval
function will return 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
If one looks into eval
and exec
source code in CPython 3, this is very evident; they both call PyEval_EvalCode
with same arguments, the only difference being that exec
explicitly returns None
.
Syntax differences of exec
between Python 2 and Python 3
One of the major differences in Python 2 is that exec
is a statement and eval
is a built-in function (both are built-in functions in Python 3).
It is a well-known fact that the official syntax of exec
in Python 2 is exec code [in globals[, locals]]
.
Unlike majority of the Python 2-to-3 porting guides seem to suggest, the exec
statement in CPython 2 can be also used with syntax that looks exactly like the exec
function invocation in Python 3. The reason is that Python 0.9.9 had the exec(code, globals, locals)
built-in function! And that built-in function was replaced with exec
statement somewhere before Python 1.0 release.
Since it was desirable to not break backwards compatibility with Python 0.9.9, Guido van Rossum added a compatibility hack in 1993: if the code
was a tuple of length 2 or 3, and globals
and locals
were not passed into the exec
statement otherwise, the code
would be interpreted as if the 2nd and 3rd element of the tuple were the globals
and locals
respectively. The compatibility hack was not mentioned even in Python 1.4 documentation (the earliest available version online); and thus was not known to many writers of the porting guides and tools, until it was documented again in November 2012:
The first expression may also be a tuple of length 2 or 3. In this case, the optional parts must be omitted. The form
exec(expr, globals)
is equivalent toexec expr in globals
, while the formexec(expr, globals, locals)
is equivalent toexec expr in globals, locals
. The tuple form ofexec
provides compatibility with Python 3, whereexec
is a function rather than a statement.
Yes, in CPython 2.7 that it is handily referred to as being a forward-compatibility option (why confuse people over that there is a backward compatibility option at all), when it actually had been there for backward-compatibility for two decades.
Thus while exec
is a statement in Python 1 and Python 2, and a built-in function in Python 3 and Python 0.9.9,
>>> exec("print(a)", globals(), {'a': 42})
42
has had identical behaviour in possibly every widely released Python version ever; and works in Jython 2.5.2, PyPy 2.3.1 (Python 2.7.6) and IronPython 2.6.1 too (kudos to them following the undocumented behaviour of CPython closely).
What you cannot do in Pythons 1.0 - 2.7 with its compatibility hack, is to store the return value of exec
into a 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
(which wouldn't be useful in Python 3 either, as exec
always returns None
), or pass a reference to exec
:
>>> call_later(exec, 'print(42)', delay=1000)
File "<stdin>", line 1
call_later(exec, 'print(42)', delay=1000)
^
SyntaxError: invalid syntax
Which a pattern that someone might actually have used, though unlikely;
Or use it in a list comprehension:
>>> [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
which is abuse of list comprehensions (use a for
loop instead!).
这篇关于eval、exec 和 compile 之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!