eval是一个类似于exec的内置函数。把一个字符串当成一个表达式来执行, 返回表达式执行后的结果。
语法:
eval(string_code, globals=None, locals=None)
x = 100
y = 200
# 执行x+y
# z = x + y
z1 = x + y
z2 = eval("x+y")
print(z1)
print(z2)
300
300
从上式可以看出,z1、z2语句不同,输出结果一样,eval就是能将字符串里内容执行后并返回。
跟eval函数类似,能够将字符串当一个表达式来执行,但是不能返回执行的结果,而是一个None。
语法:
exec(string_code, globals=None, locals=None)
# exec示例
x = 100
y = 200
# 执行x+y
# z = x + y
z1 = x + y
# 1, 注意字符串中引号的写法
# 2. 比对exec执行结果和代码执行结果
z2 = exec("print('x+y:', x+y)")
print(z1)
print(z2)
x+y: 300
300
None
eval()、exec()函数都能和print()函数一样,直接打印出内部的元素。
调用函数exec时只给它提供一个参数绝非好事。在大多数情况下,还应向它传递一个命名空间----用于放置变量的地方。否则代码将修改你的变量。例如代码使用了名称sqrt:
from math import sqrt
exec("sqrt=1")
sqrt(4)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in ()
1 from math import sqrt
2 exec("sqrt=1")
----> 3 sqrt(4)
TypeError: 'int' object is not callable
可见sqrt方法的变量名已被取代。那么为何要将字符串作为代码执行呢?函数主要用于动态地创建代码字符串。如果这种字符串来自其他地方(可能是用户),就几乎无法确定他将包含什么内容。因此为了安全起见,要提供一个字典以充当命名空间。
可将命名空间视为放置变量的地方,类似于一个看不见的字典。当执行x=1时,将在当前命名空间存储键x和值1.
所以,可以在exec中添加第二个参数----字典,用作代码字符串的命名空间。
from math import sqrt
scope={}
exec('sqrt=1',scope)
print(sqrt(4))
print(scope['sqrt'])
---------------------------------------------------------------------------
2.0
1
很明显,可能带来破坏的代码没有覆盖函数sqrt,而通过exec执行赋值语句创建的变量位于scope中。
请注意,如果想将scope打印出来,将发现它包含很多内容,这是因为自动在其中添加了包含所有内置函数和值的字典__builtins__。
print(len(scope))
print(scope.keys())
2
dict_keys(['__builtins__', 'sqrt'])