python eval函数基础介绍

liftword14小时前技术文章4


Eval函数是python的一个内置函数,作用是将字符串作为有效的Python表达式来求值,并返回计算结果。

Eval的基本语法是 eval(字符串,可选全局命名空间,可选局部命名空间)


我们来举个简单的例子。比如 "3+5" 用引号括起来的话是个字符串。如果直接打印,那就是打印出这个字符串。但是如果加上eval函数,那么就会把这个字符串当成一个python语句来运行,得到的结果就是8。


print("3+5") # 输出:3+5(字符串)

print(eval("3+5")) # 输出:8(表达式计算结果)


当然,eval里的字符串必须是有效的Python表达式,否则会抛出异常。


这个字符串里面还可以包含变量。比如定义个变量 x ,然后在eval里面使用这个变量,这样也可以正常运行。


x = 10

result = eval("x * 5") # 等价于计算 10*5

print(result) # 输出:50


Eval的后面两个参数是命名空间,其中全局命名空间必须是字典类型。局部命名空间可以是字典类型,或者其他映射对象。

当全局命名空间不为空时,就会覆盖其他全局变量,也就是前面代码里的变量就不能使用了。

比如我们指定个空字典作为参数,运行就会因“未定义变量x”出错。但把它设置为 None 值,指定个空的局部命名空间就不会有影响。如果全局和局部命名空间定义了同一个变量的话,会使用局部命名空间的值。比如在这里定义一下 x ,这样使用的就是后面这个 x 的值。


x = 100 # 全局变量

# 全局命名空间为空字典(覆盖原有全局变量x)

eval("x + 5", {}) # 报错:name 'x' is not defined


# 全局命名空间为None(使用原有全局变量x),局部命名空间为空

result = eval("x + 5", None, {}) # 正常运行,结果为105

print(result)

# 局部命名空间覆盖全局变量

result = eval("x + 5", {"x": 20}, {"x": 30}) # 局部x=30,结果为35

print(result)


利用eval函数,我们可以用来动态执行一些简单的代码片段。比如,在简单的配置文件场景中,可以规定一个字典形式的配置文件,获得配置字符串后,利用eval,直接得到每个配置参数的值,无需手动去处理字符串信息。


config_str = "{'width': 800, 'height': 600}"

config = eval(config_str) # 直接将字符串解析为字典

print(config['width']) # 输出:800


再比如,要开发一个简单的计算器,传统方式可能是,让用户输入两个数字和要做的加减等操作,获得输入后在后续代码里再判断这个操作,对两个数字进行处理。

如果用eval,就可以让用户输入整条式子,直接把整条式子转成python表达式得出计算结果。比如用户可以直接输入 1+2*3 ,运行就可以直接得到计算结果了。


user_expr = "1 + 2 * 3"

result = eval(user_expr) # 直接计算表达式

print(result) # 输出:7


正确的使用eval函数可以带来很多便利。但是eval函数最大的风险在于,如果使用不当,可能导致代码注入攻击。例如,如果eval的参数直接来源于用户输入,攻击者可以通过构造恶意字符串,执行任意Python代码,造成严重的安全问题。

就像刚才我们的简单计算器的例子,我们是期望用户会输入数学式子,但是如果是恶意用户,可能就会输入一些破坏性代码。我们这里简单的输入一个打印代码,可以看到打印代码也正常执行了。这样攻击者可以通过构造恶意字符串,对系统造成破坏。


# 危险示例:恶意用户输入可执行任意代码

malicious_input = "import os; os.system('rm -rf /')" # 警告:切勿实际运行!

eval(malicious_input) # 可能导致系统文件被删除


所以使用eval时,一般要避免让用户直接传入,除非进行严格的过滤和验证。还可以通过命名空间来做一些限制。

比如我们定义一个字典,使用 {'__builtins__':{}} ,就可以禁用所有内置函数了。这样输入打印代码或者其他函数代码,就会出错。但是输入简单表达式还是可以正常运行。


# 禁用所有内置函数(包括print)

safe_globals = {"__builtins__": {}}

eval("print('执行')", safe_globals) # 报错:name 'print' is not defined


# 允许的简单计算

result = eval("100 - 50", safe_globals)

print(result) # 输出:50


也可以指定允许运行的函数,比如加上 sum 函数,这样用户就可以输入 sum 函数直接运行了。


allowed_globals = {"__builtins__": {"sum": sum}} # 仅允许sum函数

result = eval("sum([1, 2, 3])", allowed_globals)

print(result) # 输出:6


还有其他库的替代方案,比如如果只是想解析数学表达式,可以用 ast 库的 literal_eval() 方法,这样安全性就更有保障。


import ast

safe_result = ast.literal_eval("10 * (2 + 3)") # 仅允许安全表达式

print(safe_result) # 输出:50


关于eval就介绍到这里,还有什么需要补充的,欢迎在评论区留言探讨。

相关文章

为什么计算机中0.1+0.2不等于0.3?

1+2=3,这是我们小时候就学过的一位数加减法。这道题非常简单,难度仅次于1+1=2.什么?你觉得2-1=1更简单?啊这。显然,按照常理来讲,0.1+0.2当然等于0.3对于刚上小学二年级的小王来说事...

Python 空值(None)详解

在Python中,空值是一个非常重要的概念,表示"没有值"或"空"的状态。让我们来详细了解一下。什么是空值?在Python中,空值用None表示。它是一个特殊的数据类型...

自学python第九天:布尔表达式和关键字in的示例代码

布尔表达式和关键字in的用法在Python中,“if”语句后面的条件表达式会被求值为布尔值(True或False)。当条件表达式的结果为True时,执行“if”块内的代码;否则跳过。代码:foods_...

每天学点Python知识:常量

在 Python 这门语言里,常量(constant)这个概念常常让初学者有些迷糊。毕竟,在很多其他语言中,我们可以用 const 或 final 来显式声明某个变量为常量,确保它的值不会被修改。而...

python中数值比较大小的8种经典比较方法,不允许你还不知道

在 Python 中比较数值大小是基础但重要的操作。以下是 8 种经典比较方法及其应用场景,从基础到进阶的完整指南:1. 基础比较运算符Python 提供 6 种基础比较运算符:a, b = 5, 3...

Python基础之变量、循环、函数(一)

本系列内容所用Python版本为anaconda,直接浏览器搜索下载安装即可!本次内容将为大家重点介绍Python的基础概念变量、循环、函数。一、变量变量是编程语言最重要的概念之一,变量标记或指向一个...