What's the difference between eval, exec, and compile?
我一直在研究python代码的动态评估,遇到了
有人能解释一下
简短的回答,或tl;dr
基本上,
python中的表达式可以作为变量赋值中的值:好的。
1 | a_variable = (anything you can put within these parentheses is an expression) |
在版本1.0-2.7中,
在python 3中,
因此,基本上:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> 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 |
号
1 2 3 4 5 | >>> 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 |
在
1 2 3 4 5 6 7 | >>> 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源代码)传递给
如果将包含python字节码的
1 2 3 | >>> eval(compile('if 1: print("Hello")', '<string>', 'exec')) Hello >>> |
即使编译的代码包含语句,也可以毫无问题地工作。它仍然返回
在
1 2 3 4 5 6 7 | >>> 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 |
。答案越长,A.K.A.就越详细。
1 2 3 4 5 6 7 8 9 | >>> program = ''' for i in range(3): print("Python is cool") ''' >>> exec(program) Python is cool Python is cool Python is cool >>> |
在
/好的。
1 2 3 4 5 | >>> a = 2 >>> my_calculation = '42 * a' >>> result = eval(my_calculation) >>> result 84 |
/好的。
如果一个
/好的。
1 | exec(compile(source, '<string>', 'exec')) |
和
/好的。
1 | eval(compile(source, '<string>', 'eval')) |
由于所有的表达式可以用来作为statements在Python(这些都是被称为"
/好的。
1 2 3 4 5 6 7 8 9 10 | >>> 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,只读
/好的。
1 2 3 4 5 6 7 8 9 10 11 | >>> 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 |
两
/好的。
1 2 3 4 5 6 7 | >>> g = dict() >>> l = dict() >>> exec('global a; a, b = 123, 42', g, l) >>> g['a'] 123 >>> l {'b': 42} |
(如果你显示的值在整个
/好的。
在Python中,官方的语法的
/好的。
1 | >>> exec 'global a; a, b = 123, 42' in g, l |
然而在alternate语法有
/好的。
在
/好的。
-
'eval' 模式expects一个单一的表达,和将产生的字节码,运行时,将返回的值,这表示:/好的。
1
2
3
4
5>>> 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任何生物从单建筑的Python表达式的全部模块的代码,和executes为他们,如果他们的顶级statements模块。面向None 时返回的代码:/好的。
1
2
3
4
5
6
7>>> 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' 接受源代码语句(含单或多用if语句分隔; )最后的语句表达的语句是一个字节码的产生,也无论是在repr 的值到标准输出(表达)。。。。。。。。一
if -elif -else 环链,它具有与else 和try except ,else 和finally 块是一个单一的语句。的源程序,含2顶层语句片段是一个错误的
'single' 这样,Python中的2有一个错误,也允许多toplevel语句在代码是只读的第一;编译;其余是ignored:2.7.8在Python的:
1
2
3
4>>> exec(compile('a = 5
a = 6', '<string>', 'single'))
>>> a
53.4.2和Python中的:
1
2
3
4
5
6
7
8>>> 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这是非常有用的用于制作交互式解释器shell。然而,表达的是不返回值的,即使你的
eval 产生的代码。
因此,最大的区别是:
此外,compiling到字节码的源代码,支持compiling
而只让你来评价
1 2 3 4 5 6 7 | >>> 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 |
它与
1 2 3 4 5 6 | >>> 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 |
如果一个看起来在源代码中的实现和
协会之间的语法差异
一个主要的区别是,Python中的一个表2和
不像大多数的Python 2到3的移植指南似乎suggest
由于不希望破坏与python 0.9.9的向后兼容性,guido van rossum在1993年添加了一个兼容性黑客:如果
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.Ok.
号
是的,在CPython 2.7中,它被简单地称为一个前向兼容性选项(为什么人们会因为有一个后向兼容性选项而感到困惑),实际上,它已经存在了20年的向后兼容性。好的。
因此,虽然
1 2 | >>> exec("print(a)", globals(), {'a': 42}) 42 |
可能在所有广泛发布的Python版本中都有相同的行为;在Jython 2.5.2、Pypy2.3.1(Python2.7.6)和Ironpython 2.6.1中也有相同的行为(他们对CPython的未记录行为赞不绝口)。好的。
在pythons 1.0-2.7中,您不能用兼容性hack将
1 2 3 4 5 6 7 8 | 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中也不有用,因为
1 2 3 4 5 | >>> call_later(exec, 'print(42)', delay=1000) File"<stdin>", line 1 call_later(exec, 'print(42)', delay=1000) ^ SyntaxError: invalid syntax |
这是一种可能有人实际使用的模式,尽管可能性不大;好的。
或者用它来理解列表:好的。
1 2 3 4 5 | >>> [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 |
。
这是滥用列表理解(使用
1 2 3 4 5 6 | 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) print(6)') # prints 5{newline}6. exec('if True: print(6)') # prints 6. exec('5') # does nothing and returns nothing. |
1 2 3 4 5 | 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. |
号
exec是for语句,不返回任何内容。eval用于表达式,并返回表达式的值。
表达式的意思是"某物",而语句的意思是"做某物"。