eval 与 exec, compile区别
-
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用于语句,但不返回任何内容。 eval用于表达式并返回表达式值。
表达式表示"something"而语句表示"做点什么"。
简短答案或者 TL ;DR
eval
和 exec
有 2个差异:
-
eval
返回被求值的字节码返回的值。exec
忽略返回值并总是返回None
( 在 python 2中,它是一个语句,不能用作表达式,所以它实际上不返回任何内容) 。因此:
>>> eval('42') 42 >>> exec('42') >>>
-
如果包含的
code
对象被传递给exec
或者eval
,它们的行为就会相同,除了返回值(eval
返回返回的值,exec返回None
) 。如果一个包含源代码的字符串被传递给
exec
/eval
,它在内部编译为使用compile(source, '<string>', mode)
其中mode
分别为exec
或者eval
。 这就是不同之处所在。
中的compile
'exec'
模式集成任意数量的语句做成一字节码可以隐式地总是返回 None
,然而在 'eval'
模式下,它只编译一个单表达式转换为字节码可以返回出表达式的值。
>>> eval(compile('42', '<string>', 'exec')) # code return 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
将引发异常:
>>> 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
答案越长,a.k.a的细节就越多
exec
和 eval
exec
函数( 在 python 2, 哪个是一个语句) 用于执行动态创建的语句或者程序:
>>> program = 'for i in range(3):\n 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.k.a 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
- 它们是代码所看到的全局和局部变量作用域。 这些默认到名为 exec
或者 eval
的作用域内的globals()
和 locals()
,但是任何字典都可以用于 globals
和 locals
( 当然包括 dict
)的任何 mapping
。 这些不仅可以用来限制/修改代码所看到的变量,还可以用于捕获 exec
代码创建的变量:
>>> g = {}
>>> l = {}
>>> exec('global a; a, b = 123, 42', g, l)
>>> g['a']
123
>>> l
{'b': 42}
( 如果你显示整个 g
的值,则会更长,因为 exec
和 eval
将built-ins模块作为 __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
或者通过将源代码编译成一个 code
eval
对象的调用。 mode
参数控制 compile
函数接受的代码Fragment类型以及它生成的字节码类型。 选择是 'eval'
,'exec'
和 'single'
:
'eval'
需要一个单独的表达式,并且会产生字节码,当运行时会返回表达式的值'exec'
接受从单个表达式到整个代码模块的任何类型的python 构造,并将它们作为模块top-level语句执行-
'single'
是一种有限形式的'exec'
包含一个单 语句它能接受一个源代码;如果是表达式语句,它的repr
是print
艾德到标准 output() 。!一个
if
-elif
-else
链,一个带有else
的循环,和try
,else
和finally
块的被认为是一个单一语句。一个源 Fragment,包含 2 top-level语句是错误对于
'single'
,除在 python 2有一个 Bug 死亡,它允许多个顶级中的语句代码,只有第一个会被编译的,其余的将被忽略:在 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
函数及其模式。
python,只关心calls,除了编译源代码到字节码,compile
支持编制 抽象语法树 ( python 代码的解析树) 成 code
物件,并且在 ast.parse
被写入源代码编译成抽象语法树(compile(source, filename, mode, PyCF_ONLY_AST)
这些代码用于动态地修改源代码,也用于动态代码创建,因为在复杂情况下将代码作为节点的树而不是文本行更容易处理。
而 eval
仅允许你计算一个字符串包含单个表达式,可以 eval
完整的语句,甚至是一个整体模块,它已经与 python compile
d 成字节码,也就是说,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
它与 'exec'
模式成一个 code
对象并且可以 compile
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 -to-3 移植 指南 似乎 来建议 CPython中,则 exec
语句 2可以也与语法,该语法使用看起来 到底与候车室的exec
函数调用 python 3 。 原因是 python 0.9.9有 exec(code, globals, locals)
内置函数 ! ,而且内置函数被换成 exec
语句之前的某个位置 python 1.0释放 。
在 1993, 因为是可取途径不破坏向后兼容性与 python 0.9.9,一个 guidovanrossum添加了一个兼容 如果 code
是长度为 2或者 3的元组,并且 globals
和 locals
没有传递到 exec
语句,那么 code
将被解释为该元组的2和 3个元素分别是 globals
和 locals
。 兼容性 hack 未提到即使在 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,它是可以方便简单的被称为作为一个为 ( 为什么会让人困惑,因为有一个向后兼容的选项) forward-compatibility选项,当它实际上要在那儿为二十年 backward-compatibility 。
因此,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 ) 和 2.6.1过( 他们对CPython的未记录在案行为的赞扬) 。