python 有趣的语法糖 之 eval

85 阅读3分钟

python eval()

eval(expression, globals=None, locals=None) eval()方法解析expression, 并将值返回

参数

expression: 解析的表达式 globals: 字典格式 locals: 官方解释只要是map对象就行,我们一般使用字典 具体globalsloclas怎么用下方例子说明

返回

返回expression的值

例1:

x=1
print(eval("x + 1"))

输出 2

例2

# Perimeter of Square
def calculatePerimeter(l):
    return 4*l

# Area of Square
def calculateArea(l):
    return l*l


expression = input("Type a function: ")

for l in range(1, 5):
    if (expression == 'calculatePerimeter(l)'):
        print("If length is ", l, ", Perimeter = ", eval(expression))
    elif (expression == 'calculateArea(l)'):
        print("If length is ", l, ", Area = ", eval(expression))
    else:
        print('Wrong Function')
        break

输出:

Type a function: calculateArea(l)

If length is 1 , Area = 1

If length is 2 , Area = 4

If length is 3 , Area = 9

If length is 4 , Area = 16

不安全警告:

如果你在使用Unix系列的系统,并且你导入了os模块, 那么所有的用户都可再eval(input())中输入os.system('rm -rf *')删除所有文件夹 那么eval执行的表达式中变量是怎么规定的: 下面

print(eval("a + 1"))

是不能通过的, 因为再这个程序内并没有声明a 正确的方式是:

a = 1024
print(eval("a + 1"))

我们可以使用dir()来查看允许使用的变量都有什么: 如果没有导入math模块:

print(eval("dir()"))

输出:

['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']

导入math模块:

from math import *
print(eval("dir()"))

输出:

['annotations', 'builtins', 'doc', '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', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']

你会发现多了很多的数学方法

如何解决不安全的问题:

我们可使用globalslocals来规定变量

  1. globals是None
from math import *
print(eval("dir", {}))
print(eval("sqrt(25)", {}))

输出:

['builtins']

Traceback (most recent call last):

File "", line 5, in

print(eval('sqrt(25)', {}))

File "", line 1, in

NameError: name 'sqrt' is not defined

如果globals传入空值,那么只有__builtins__是可以用的, 也就是说只有那些不用导入就能只用的变量才能用(列表, 元组, 字典)

  1. 我们只允许使用部分变量,来防止不安全发生
from math import *
print(eval("dir()", {"sqrt": sqrt, "pow':pow}))

输出 ['__builtins__', 'pow', 'sqrt']

  1. 当然可以使用自定义的名字
from math import *
names = {'square_root': sqrt, 'power': pow}
print(eval('dir()', names))

# Using square_root in Expression
print(eval('square_root(9)', names))

输出

['__builtins__', 'power', 'square_root']
3.0

如果使用自定义名字, 那么你在使用sqrt是会报错的。

  1. 禁止使用不用导入的模块:
# calculate the length of a tuple
eval("len((1,2,3,4))", {'__builtins__': None})

输出


TypeError Traceback (most recent call last) in ----> 1 print(eval("len((1,2,3,4))", {"builtins":None}))

in

TypeError: 'NoneType' object is not subscriptable

  1. globalslocals的区别: eval会首先再local中查找,如果没有查找到变量或方法,就会在global中查找。 ==下面的例子默认执行from math import *==
eval("dir()", {"sqrt":sqrt, "sin":sin}, {"pow":pow, "sqrt":sqrt})

输出 ['pow', 'sqrt']

eval("sin_loc(1)", {"sqrt":sqrt, "sin_glo":sin}, {"pow":pow, "sqrt":sqrt, "sin_loc":sin})

0.8414709848078965

eval("sin_glo(1)", {"sqrt":sqrt, "sin_glo":sin}, {"pow":pow, "sqrt":sqrt, "sin_loc":sin})

0.8414709848078965

虽然math中有sin()方法, 凡是在globals和'locals'中并没设置,所以异常 eval("sin(1)", {"sqrt":sqrt, "sin_glo":sin}, {"pow":pow, "sqrt":sqrt, "sin_loc":sin})


NameError Traceback (most recent call last) in ----> 1 eval("sin(1)", {"sqrt":sqrt, "sin_glo":sin}, {"pow":pow, "sqrt":sqrt, >"sin_loc":sin})

in

NameError: name 'sin' is not defined