eval()语法及使用
eval()方法会解析传入该方法的表达式,并且会在程序中运行解析后的表达式。换句话说,它会将一个字符串解析成代码来执行。
STNTAXeval(expression, GLOBALS=None, LOCALS=None)
- expression: 传入的表达式
- GLOBALS: 全局方法或者变量的字典
- LOCALS: 局部方法或者变量的字典
该方法返回表达式执行的结果。
接下来我们来创建表达式并运行程序来评估该表达式。
USAGE
user_expr = raw_input("请输入一个关于变量a的表达式:")
a = int(raw_input("请输入变量a的值:"))
result = eval(user_expr)
print("result = {}".format(result))
Output
请输入一个关于变量a的表达式: a ** 2 + 1
请输入变量a的值: 3
result = 10
Security Issue With eval()
假设你导入了os模块,os模块提供了一种快捷的方式来操作诸如读写文件这样的操作系统函数。如果你允许用户使用eval(input())的方式输入一个值,用户可能会输入改变系统文件的命令,甚至会输入像os.system('rm -rf *')
这样的命令删除整个系统文件。那么,在你的代码中使用eval(input())来检查用户可以使用的方法和变量不失为一个好主意,你可以使用dir()方法来查看哪些方法和变量是可用的。
from math import *
print(eval('dir()'))
Output
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'os', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
在eval()中限制可用方法和变量的使用
大多数情况下,在expression
中使用的方法和变量都不是必须的,甚至会造成安全漏洞。你可能需要限制这些方法和变量的使用,你可以通过像eval()
中传入globals
和locals
参数来达到这一目的。
1.省略globals和locals参数
如果globals
和locals
参数都被省略掉,那么expression
会在当前范围内执行,你可以使用下面的方法来检查可用的方法和变量
print(eval(dir()))
2.只传入globals参数
globals
参数和locals
参数(字典)分别作用于全局变量和局部变量。如果省略了locals
字典,那么其默认值是globals
字典。意思就是,globals
字典会同时作用于全局变量和局部变量。
你可以使用python的内置方法globals()和locals()来分别检查当前的全局变量和局部变量。
3.传入一个空字典作为globals参数
from math import *
print(eval('dir()', {}))
# 下面的代码会抛出异常
print(eval('sqrt(25)', {}))
Output
['__builtins__']
Traceback (most recent call last):
File "<string>", line 5, in <module>
print(eval('sqrt(25)', {}))
File "<string>", line 1, in <module>
NameError: name 'sqrt' is not defined
如果你传入一个空字典作为globals
参数,那么只有__builtins__
方法是可用的,即使我们导入了math
模块,expression
也不能访问任何math
模块提供的方法。
4.指定某些方法可用
from math import *
print(eval('dir()', {'sqrt': sqrt, 'pow': pow}))
Output
['__builtins__', 'pow', 'sqrt']
在这里,expression只能使用sqrt()、pow()以及__builtins__方法。当然,你也可以根据你的喜好来改变可用方法的名字:
from math import *
names = {'square_root': sqrt, 'power': pow}
print(eval('dir()', names))
# 在表达式中使用别名
print(eval('square_root(9)', names))
Output
['__builtins__', 'power', 'square_root']
3.0
在上面的例子中,如果尝试直接使用sqrt()
方法,程序会抛出错误。
5.限制built-ins的使用
你可以通过下面的方法限制expression
对__builtins__
的使用:
eval(expression, {'__builtins__: None})
6.传入globals和globals参数
from math import *
a = 169
print(eval('sqrt(a)', {'__builtins__': None}, {'a': a, 'sqrt': sqrt}))
Output
13.0
在这个例子中,expression
能并且只能使用sqrt()
方法和变量a
,其它的所有方法和变量都不能够使用。
通过globals
和locals
参数的传递来限制eval()
的用法可以让你的代码更加安全,尤其是在使用用户通过input()
方法给eval()
传参的时候。
有时候,即使限制eval()可使用的方法和变量也不是安全的,当一个对象和它的的方法是可访问的,几乎可以做任何事,这时候唯一安全的方法就是验证用户输入的有效性。
整理自:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。