python中eval的真香定律

2020年12月16日 213点热度 2人点赞 0条评论
eval 是python中的一个内置函数,非常强大,也非常灵活,但是你得慎用
不然……

所以,本文从 “真香” 和 “真相” 这两方面以实例的形式介绍eval
知己知彼百战不殆
语法格式:
eval(expression, globals=None, locals=None)
参数解析:
  • expression:这个参数是一个字符串,python会使用globals字典和locals字典作为全局和局部的命名空间,将expression当做一个python表达式进行解析和计算。
  • globals:这个参数控制的是一个全局的命名空间,也就是我们在计算表达式的时候可以使用全局的命名空间中的函数,如果这个参数被提供了,并且没有提供自定义的__builtins__,那么会将当前环境中的__builtins__拷贝到自己提供的globals里,然后才会进行计算。关于__builtins__,它是python的内建模块,也就是python自带的模块,不需要我们import就可以使用的,例如我们平时使用的int、str等都在这个模块中。如果globals没有被提供,则使用python的全局命名空间
  • locals:这个参数控制的是一个局部的命名空间,和globals类似,不过当它和globals中有重复的部分时,locals里的定义会覆盖掉globals中的,也就是当globals和locals中有冲突的部分时,locals说了算,它有决定权,以它的为准。如果locals没有被提供的话,则默认为globals。
“真香”之忽略globals和locals:
a = 1
eval('a+1')
Out[2]: 2
在这种情况下,省略了后面两个参数,所以eval中a是前面的数字1,eval会将expression字符串参数的引号去掉,对引号中的表达式进行解析和计算。
再来一个例子:a为一个列表形式的字符串
a = "[[1,2],[3,4]]" 
type(a) 
Out[4]: str 
eval(a) 
Out[5]: [[1, 2], [3, 4]] 

type(eval(a)) 
Out[6]: list
我们一直在强调,将expression当做一个python表达式进行解析和计算,所以说一定要确保第一个参数expression满足表达式的要求,是可以被解析然后计算的
a = "a,b,c,d" 
type(eval(a)) 

NameError: name 'b' is not defined
对于上面的代码,可以看到,字符串a并不满足表达式的要求。当eval剥去了"a,b,c,d"外面的引号的时候,会对它进行解析,满足要求后进行计算,然后它解析得到的是a,b,c,d,注意,程序报出的错误是NameError,也就是说,当它解析到这个表达式是不可以计算后,它就会查找它是不是一个变量的名字,如果是一个变量的名字,那么它会输出这个变量的内容,否则就会产生NameError
In [9]: a = 1 
In [10]: b = 2 
In [11]: c = "a,b" 
In [12]: eval(c) 
Out[12]: (1, 2)
在python中,对字符串的定义,可以使用单引号、双引号、三引号、引号之间的嵌套,对于这种类型的字符串,eval将会怎么处理?
延用上面的代码:
In [12]: eval(c) 
Out[12]: (1, 2) 

In [13]: eval('c') 
Out[13]: 'a,b'
此处不做更多赘述,参考下a = "a,b,c,d"处代码解释。
“真香”之使用globals
In [15]: eval("{'name':'abu','age':age}",{"age":18}) 
Out[15]: {'name': 'abu', 'age': 18}
“真香”之使用globals和locals
In [16]: age = 20 
In [17]: eval("{'name':'abu','age':age}",{"age":18},locals()) 

Out[17]: {'name': 'abu', 'age': 20}
“真相”之评估
eval虽然强大、灵活,但是它可以将字符串转化为表达式并执行,就显得有点可怕了。我们知道在企业生产环境中,一般为centos系统,而这个系统中默认是安装python环境的。如果有人执行一些不友好的命令,是不是感觉脊背发凉?
[root@abu ~]# echo "I'm eval" > testEval.txt 
[root@abu ~]# python 
>>> eval("__import__('os').system('ls /root')") 
testEval.txt 
0 
>>> eval("__import__('os').system('cat /root/testEval.txt')") 
I'm eval 
0
我想这也是为什么函数名叫eval的原因吧?评估风险,合理使用!
所以,我们要:持证上岗!

阿布

源自灵魂深处的自我救赎。

文章评论