Python eval()exec()函数

eval()exec()函数都属于Python的内置函数, 它们的功能是类似的, 都可以执行一个字符串形式的Python代码(代码以字符串的形式提供), 相当于一个Python的解释器. 二者的不同之处在于, eval()执行完要返回结果, 而exec()执行完不返回结果.

用法

eval()函数的语法格式为:

eval(expression, global=None, local=None, /)

exec()函数的语法格式如下:

exec(expression, global=None, local=None, /)

可以看到, 二者的语法格式除了函数名, 其它都相同, 其中各个参数的具体含义如下:

  • expression

这个参数是一个字符串, 代表要执行的语句. 该语句受后面两个字典类型参数globalslocals的限制, 只有在globals字典和locals字典作用域范围内的函数和变量才能被执行;

  • globals

这个参数管控的是一个全局的命名空间, 即expression可以使用全局命名空间中的函数. 如果只是提供了globals参数, 而没有提供自定义的__builtins__, 则系统会将当前环境中的__builtins__复制到自己提供的globals中, 然后才会进行计算; 如果连globals这个参数都没有提供, 则使用Python的全局命名空间.

  • locals

这个参数管控的是一个局部的命名空间, 和globals类似, 当它和globals中有重复或冲突时, 以locals的为准. 如果locals没有被提供, 则默认为globals.

注解

__builtin__是Python的内建模块.

globals参数使用示例:

dic = {} # 定义一个空字典
dic['b'] = 10 # 在dic中添加一个元素, key为b
print(dic.keys()) # 先将dic的key打印出来, 有一个元素b
exec('a = 20', dic} # 在exec执行的语句后面跟一个作用域dic
print(dic.keys()) # 执行exec后, dic的key多了一个

运行结果为:
dict_keys(['b'])
dict_keys(['b', '__builtins__', 'a'])

上面的代码是在作用域dic下执行了一句a = 4的代码. 可以看出, exec()之前dic的key中只有一个b. 执行完exec()之后, 系统在dic中生成了两个新的key, 分别是a__builtins__. 其中, a为执行语句生成的变量, 系统将其放到指定的作用域字典里; __builtin__是系统加入的内置key.

locals参数使用示例:

a = 10
b = 20
c = 30
d = 200
g = {'a': 40, 'b': 50}
l = {'b': 60, 'c': 70}
print(eval('a + b + c', g, l))

运行结果为:
170

eval()exec()的区别

它们的区别在于, eval()执行完会返回结果, exec()执行完不返回结果.

Example:

a = 1
exec('a = 2') # 相当于执行a = 2
print(a)
a = exec('2 + 10') # 相当于执行2 + 10, 但是没有返回值, a应该为None
print(a)
a = eval('2 + 10') # 执行2 + 10, 并把结果返回给a
print(a)

运行结果为:
2
None
12

如果在eval()里放置了一个没有结果返回的语句, 则Python解释器会报SyntaxError错误.

Example:

a = eval('a = 200')

运行结果为:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
    a = 200
      ^
SyntaxError: invalid syntax

注意事项

使用eval()exec()函数时, 一定要记住, 它们的第一个参数是字符串, 而字符串的内容一定要是可执行的代码.

eval()函数为例, 用代码演示常犯的错误:

s = 'hello'
print(eval(s))

运行结果如下:

Traceback (most recent call last):
File "./demo.py", line 4, in <module>
    print(eval(s))
File "<string>", line 1, in <module>
NameError: name 'hello' is not defined

上面例子出错的地方在于, 字符串的内容是hello, 而hello并不是可执行的代码(除非定义了变量叫做hello).

如果要将字符串hello通过print函数打印出来, 可以写成如下的样子:

s = 'hello'
print(eval('s'))

运行结果为:
hello

这种写法是要eval()执行'hello'这句代码. 这个hello是有引号的, 在代码中代表字符串的意思, 所以可以执行.

同理, 也可以写成这样:

s = '"hello"'
print(eval(s))

运行结果为:
hello

这种写法的意思是s是个字符串, 并且其内容是个带引号的hello, 所以直接将s放入到函数eval()中也可以执行.

除了以上几种方式, 还可以不去改变原有字符串s的写法, 直接使用repr()函数来进行转化, 也可以得到同样的效果.

Example:

s = 'hello'
print(eval(repr(s)))

运行结果为:
hello

注意, 虽然函数repr()str()的返回值都是字符串, 但是使用str()函数对s进行转换, 程序同样会报错:

s = 'hello'
print(eval(str(s)))

运行结果为:

Traceback (most recent call last):
File "./demo.py", line 4, in <module>
    print(eval(str(s)))
File "<string>", line 1, in <module>
NameError: name 'hello' is not defined

为什么会有这个区别呢? 同样对字符串s的转化, 使用repr()str()得到的结果是有差别的, 直接将两者的结果打印出来, 就可以明显看出不同.

s = 'hello'
print(repr(s))
print(str(s))

运行结果为:
'hello'
hello

可见, 使用repr()返回的内容, 输出后会在两边多一个单引号.

注解

在编写代码时, 一般会使用repr()函数来生成动态地字符串, 再传入到eval()exec()函数内, 实现动态执行代码的功能.