eval、exec 和compile 之间有什么区别?
我一直在研究 Python 代码的动态评估,并遇到了 eval()
和 compile()
函数以及 exec
语句。
有人可以解释一下 eval
和 exec
之间的区别,以及 compile()
的不同模式如何适应吗?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
简短的答案,或者 TL;DR
基本上,
eval
< /a> 用于评估评估单个动态生成的 Python 表达式,exec
用于execute动态生成的Python代码,只是为了它的副作用。eval
和exec
有两个区别:eval
只接受单个表达式,exec
可以采用包含 Python 语句的代码块:循环、try: except:
、class
和函数/方法def
initions 和很快。Python 中的表达式是可以作为变量赋值中的值的任何内容:
eval
返回给定表达式的值,而exec 忽略其代码的返回值,并且始终返回
None
(在 Python 2 中,它是一个语句,不能用作表达式,因此它实际上不返回任何内容)。在版本 1.0 - 2.7 中,
exec
是一条语句,因为 CPython 需要为使用exec
来消除函数内部副作用的函数生成不同类型的代码对象。在Python 3中,
exec
是一个函数;它的使用对使用它的函数的编译字节码没有影响。因此基本上:
'exec'
模式下的compile
将任意数量的语句编译为隐式始终返回None
的字节码,而在'eval'
模式它将单个表达式编译为字节码,返回该表达式的值。在
'eval'
模式下(如果传入字符串,则使用eval
函数),如果源代码存在,则compile
会引发异常代码包含语句或单个表达式之外的任何其他内容:实际上,语句“eval 仅接受单个表达式”仅在传递字符串(包含 Python 源代码)时才适用到
评估
。然后使用compile(source, '在内部将其编译为字节码;', 'eval')
这就是差异的真正来源。如果将
code
对象(包含 Python 字节码)传递给exec
或eval
,它们的行为完全相同,除了exec
忽略返回值,仍然始终返回None
。因此,如果您之前只是将其编译为字节码而不是将其作为字符串传递,那么可以使用 eval 来执行具有语句的内容:工作没有问题,即使编译后的代码包含语句。它仍然返回
None
,因为这是从compile
返回的代码对象的返回值。在
'eval'
模式下(如果传入字符串,则使用eval
函数),如果源代码存在,则compile
会引发异常代码包含语句或超出单个表达式的任何其他内容:较长的答案,又名血腥细节
exec
和eval
org/3/library/functions.html#exec" rel="noreferrer">
exec
函数(这是 Python 2 中的语句) 用于执行动态创建的语句或程序:eval
函数对 单个表达式,和返回表达式的值:exec
和eval
都接受程序/表达式作为包含源代码的str
、unicode
或bytes
对象运行,或者作为code
对象,其中包含 Python 字节码。如果将包含源代码的
str
/unicode
/bytes
传递给exec
,则其行为等同于:和 < code>eval 的行为类似地相当于:
由于所有表达式都可以用作 Python 中的语句(这些在 Python 抽象语法;相反则不然),如果你不需要返回值。也就是说,您可以使用
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()
,但任何字典可用于全局变量和本地变量的任何映射(当然包括字典)。这些不仅可以用于限制/修改代码看到的变量,而且通常还可以用于捕获 exec 代码创建的变量:(如果显示整个 < code>g,它会更长,因为
exec
和eval
将内置模块作为__builtins__
添加到全局变量中如果丢失则自动)。在 Python 2 中,
exec
语句的官方语法实际上是exec code in globals, locals
,如但是替代语法
exec(code, globals, locals )
也一直被接受(见下文)。编译
compile(源、文件名、模式, flags=0, dont_inherit=False, optimize=-1)
内置可用于加速使用exec
或重复调用相同代码eval
通过预先将源代码编译为code
对象。mode
参数控制compile
函数接受的代码片段类型及其生成的字节码类型。选项有'eval'
、'exec'
和'single'
:'eval'
模式需要单个表达式,并将生成字节码,运行时将返回该表达式的值:<前><代码>>>> dis.dis(编译('a + b', '', 'eval'))
1 0 LOAD_NAME 0 (a)
3 LOAD_NAME 1 (b)
6 二进制添加
7 返回值
< code>'exec' 接受从单个表达式到整个代码模块的任何类型的 python 构造,并像执行模块顶级语句一样执行它们。代码对象返回
None
:<前><代码>>>> dis.dis(编译('a + b', '', 'exec'))
1 0 LOAD_NAME 0 (a)
3 LOAD_NAME 1 (b)
6 二进制添加
7 POP_TOP <- 丢弃结果
8 LOAD_CONST 0(无)<- 在堆栈上加载无
11 RETURN_VALUE <- 返回栈顶
'single'
是'exec'
的有限形式,它接受包含 的源代码>单个语句(或由;
分隔的多个语句)如果最后一个语句是表达式语句,则生成的字节码还会打印该语句的repr
该表达式的值到标准输出(!)。一个
if
-elif
-else
链,一个带有else
的循环,以及try< /code> 及其
except
、else
和finally
块被视为单个语句。包含 2 个顶级语句的源代码片段是
'single'
的错误,但在 Python 2 中,存在有时允许多个顶级语句的错误代码;仅编译第一个;其余的被忽略:在 Python 2.7.8 中:
<前><代码>>>> exec(编译('a = 5\na = 6', '<字符串>', '单个'))
>>>>>一个
5
在 Python 3.4.2 中:
<前><代码>>>> exec(编译('a = 5\na = 6', '<字符串>', '单个'))”,第 1 行,在中”,第 1 行
回溯(最近一次调用最后一次):
文件“
文件“
一个= 5
^
SyntaxError:编译单个语句时发现多个语句
这对于制作交互式 Python shell 非常有用。但是,即使您
评估
生成的代码,表达式的值也不会返回。因此,
exec
和eval
的最大区别实际上来自于compile
函数及其模式。除了将源代码编译为字节码之外,
compile
还支持编译抽象语法树(Python代码的解析树)为code
对象;和源代码到抽象语法树中(ast.parse
是用Python编写的,只调用compile(source, filename, mode, PyCF_ONLY_AST)
);例如,它们用于动态修改源代码,也用于动态代码创建,因为在复杂情况下将代码作为节点树而不是文本行处理通常更容易。虽然
eval
只允许您计算包含单个表达式的字符串,但您可以eval
整个语句,甚至是已编译的整个模块
code>d 转换为字节码;也就是说,在 Python 2 中,print
是一条语句,不能直接通过eval
引导:使用
'exec'<
compile
它/code> 模式转换为code
对象,您可以eval
它;eval
函数将返回None
。如果有人查看
eval
和exec
源CPython 3 中的代码,这一点非常明显;它们都使用相同的参数调用PyEval_EvalCode
,唯一的区别是exec
显式返回None
。Python 2 和 Python 3 之间
exec
的语法差异Python 2 中的主要区别之一是
exec
是一条语句,而eval
是一个内置函数(两者都是Python 3中的内置函数)。众所周知,Python 2 中
exec
的官方语法是exec code [in globals[, locals]]
。与大多数 Python 2 到 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 年添加了一个兼容性 hack:如果
code
是长度为 2 或 3 的元组,以及globals
和locals
> 没有传递到exec
语句中,否则,code
将被解释为就好像元组的第二个和第三个元素是globals
并且分别是当地人
。即使在 Python 1.4 文档(最早的在线版本)中也没有提到兼容性黑客);因此,许多移植指南和工具的作者并不知道它,直到 于 2012 年 11 月再次记录:是的,在 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 的未记录行为表示敬意)。
在 Python 1.0 - 2.7 中你不能做的就是将 exec 的返回值存储到变量中:(
这在 Python 3 中也没有用,因为 exec 总是返回
None
),或者传递对exec
的引用:这是某人可能实际使用过的模式,尽管不太可能;
或者在列表推导式中使用它:
这是对列表推导式的滥用(请改用
for
循环!)。The short answer, or TL;DR
Basically,
eval
is used to evaluate a single dynamically generated Python expression, andexec
is used to execute dynamically generated Python code only for its side effects.eval
andexec
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:
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 usedexec
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:
The
compile
in'exec'
mode compiles any number of statements into a bytecode that implicitly always returnsNone
, whereas in'eval'
mode it compiles a single expression into bytecode that returns the value of that expression.In the
'eval'
mode (and thus with theeval
function if a string is passed in), thecompile
raises an exception if the source code contains statements or anything else beyond a single expression: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 usingcompile(source, '<string>', 'eval')
This is where the difference really comes from.If a
code
object (which contains Python bytecode) is passed toexec
oreval
, they behave identically, excepting for the fact thatexec
ignores the return value, still returningNone
always. So it is possible useeval
to execute something that has statements, if you justcompile
d it into bytecode before instead of passing it as a string: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 fromcompile
.In the
'eval'
mode (and thus with theeval
function if a string is passed in), thecompile
raises an exception if the source code contains statements or anything else beyond a single expression:The longer answer, a.k.a the gory details
exec
andeval
The
exec
function (which was a statement in Python 2) is used for executing a dynamically created statement or program:The
eval
function does the same for a single expression, and returns the value of the expression:exec
andeval
both accept the program/expression to be run either as astr
,unicode
orbytes
object containing source code, or as acode
object which contains Python bytecode.If a
str
/unicode
/bytes
containing source code was passed toexec
, it behaves equivalently to:and
eval
similarly behaves equivalent to: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 useexec
if you do not need the return value. That is to say, you can use eithereval('my_func(42)')
orexec('my_func(42)')
, the difference being thateval
returns the value returned bymy_func
, andexec
discards it:Of the 2, only
exec
accepts source code that contains statements, likedef
,for
,while
,import
, orclass
, the assignment statement (a.k.aa = 42
), or entire programs:Both
exec
andeval
accept 2 additional positional arguments -globals
andlocals
- which are the global and local variable scopes that the code sees. These default to theglobals()
andlocals()
within the scope that calledexec
oreval
, but any dictionary can be used forglobals
and anymapping
forlocals
(includingdict
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 theexec
uted code creates:(If you display the value of the entire
g
, it would be much longer, becauseexec
andeval
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 actuallyexec code in globals, locals
, as inHowever 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 withexec
oreval
by compiling the source into acode
object beforehand. Themode
parameter controls the kind of code fragment thecompile
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:'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
:'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:
And in Python 3.4.2:
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
andeval
actually comes from thecompile
function and its modes.In addition to compiling source code to bytecode,
compile
supports compiling abstract syntax trees (parse trees of Python code) intocode
objects; and source code into abstract syntax trees (theast.parse
is written in Python and just callscompile(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 caneval
a whole statement, or even a whole module that has beencompile
d into bytecode; that is, with Python 2,print
is a statement, and cannot beeval
led directly:compile
it with'exec'
mode into acode
object and you caneval
it; theeval
function will returnNone
.If one looks into
eval
andexec
source code in CPython 3, this is very evident; they both callPyEval_EvalCode
with same arguments, the only difference being thatexec
explicitly returnsNone
.Syntax differences of
exec
between Python 2 and Python 3One of the major differences in Python 2 is that
exec
is a statement andeval
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 isexec 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 theexec
function invocation in Python 3. The reason is that Python 0.9.9 had theexec(code, globals, locals)
built-in function! And that built-in function was replaced withexec
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, andglobals
andlocals
were not passed into theexec
statement otherwise, thecode
would be interpreted as if the 2nd and 3rd element of the tuple were theglobals
andlocals
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: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,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:(which wouldn't be useful in Python 3 either, as
exec
always returnsNone
), or pass a reference toexec
:Which a pattern that someone might actually have used, though unlikely;
Or use it in a list comprehension:
which is abuse of list comprehensions (use a
for
loop instead!).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
模式,但只需要一个表达式/语句,例如compile('a= 1 if 1 else 3', 'myf', mode='single')
exec
is not an expression: a statement in Python 2.x, and a function in Python 3.x. It compiles and immediately evaluates a statement or set of statement contained in a string. Example:eval
is a built-in function (not a statement), which evaluates an expression and returns the value that expression produces. Example:compile
is a lower level version ofexec
andeval
. It does not execute or evaluate your statements or expressions, but returns a code object that can do it. The modes are as follows:compile(string, '', 'eval')
returns the code object that would have been executed had you doneeval(string)
. Note that you cannot use statements in this mode; only a (single) expression is valid.compile(string, '', 'exec')
returns the code object that would have been executed had you doneexec(string)
. You can use any number of statements here.compile(string, '', 'single')
is like theexec
mode but expects exactly one expression/statement, egcompile('a=1 if 1 else 3', 'myf', mode='single')
exec 是 for 语句,不返回任何内容。
eval 用于表达式并返回表达式的值。
表达式的意思是“某事”,而陈述的意思是“做某事”。
exec is for statement and does not return anything.
eval is for expression and returns value of expression.
expression means "something" while statement means "do something".