查看: 115|回复: 0

Python eval与exec函数详解:动态执行表达式及代码示例

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
在Python编程中,动态类型系统允许开发者在运行时定义和操作变量,而内置函数eval和exec则是实现动态执行代码的两大利器。eval通常用于计算字符串形式的表达式并返回结果,exec则用于执行包含多行语句的代码块但不返回结果。两者都支持自定义全局与局部命名空间,灵活性很高,但同时也伴随着安全风险,尤其是处理不受信任的输入时必须格外谨慎。

一、eval函数的基本用法与示例
eval接收一个字符串表达式,在运行时解析并求值,最后返回计算结果。
  1. expression = "3 + 5"
  2. result = eval(expression)
  3. print(f"表达式 {expression} 的结果是:{result}")
复制代码

这是一个最简单的演示,eval将字符串"3 + 5"计算为整数8。

eval也可以动态计算包含变量的表达式,变量来自当前作用域:
  1. x = 10
  2. y = 20
  3. expression = "x * y + 5"
  4. result = eval(expression)
  5. print(f"表达式 {expression} 的结果是:{result}")
复制代码

执行结果为205。eval看到表达式里的x和y时,会从当前全局命名空间中查找对应值。

二、为eval指定命名空间
eval的完整签名是eval(expression, globals=None, locals=None)。开发者可以传入自定义字典来限制表达式可访问的变量,避免使用调用方作用域中的全部变量。
  1. global_vars = {"x": 5, "y": 10}
  2. local_vars = {"z": 2}
  3. expression = "x + y * z"
  4. result = eval(expression, global_vars, local_vars)
  5. print(f"表达式 {expression} 的结果是:{result}")
复制代码

这里global_vars提供了x和y,local_vars提供了z,最终表达式等价于5 + 10 * 2,输出25。

三、exec函数的基本用法与示例
exec可以执行包含循环、函数定义、类定义等多行语句的Python代码,但不会像eval那样返回计算结果。
  1. code = """
  2. for i in range(3):
  3.     print(f"这是第 {i} 次执行")
  4. """
  5. exec(code)
复制代码

执行后会依次输出三次文本。exec不仅可以执行普通语句,还能动态定义函数:
  1. code = """
  2. def dynamic_function(x, y):
  3.     return x + y
  4. """
  5. exec(code)
  6. result = dynamic_function(5, 3)
  7. print(f"dynamic_function(5, 3) 的结果是:{result}")
复制代码

exec会将dynamic_function的定义写入当前全局命名空间,所以调用方可以直接调用dynamic_function,最终取得结果8。

四、为exec指定命名空间
exec同样支持globals和locals两个可选参数。当需要把动态代码中产生的变量保存到显式的局部字典中,可以使用下面的写法:
  1. global_vars = {"x": 5, "y": 10}
  2. local_vars = {}
  3. code = """
  4. z = x * y
  5. """
  6. exec(code, global_vars, local_vars)
  7. print(f"z 的值是:{local_vars['z']}")
复制代码

代码在执行时从global_vars获取x和y,将计算得到的z写入local_vars。对于这种需要从exec中提取变量的场景,比依赖当前作用域更安全、清晰。

五、eval与exec的安全边界
eval和exec本质上是运行时解释器,可以执行任意传入的字符串代码。如果代码来自用户输入、外部配置文件或网络数据,攻击者可能借此读取系统文件、执行系统命令或破坏运行环境。因此两条原则需要牢记:

1. 不要用eval或exec处理不受信任的输入。
2. 如果确实需要解析表达式,优先考虑使用ast.literal_eval或其他安全解析库。

六、实际应用:基于输入动态计算表达式
一个常见的动态执行示例是命令行计算器。程序循环读取用户输入,交给eval计算并返回结果,同时捕获异常避免程序崩溃:
  1. def calculator(expression):
  2.     try:
  3.         result = eval(expression)
  4.         return result
  5.     except Exception as e:
  6.         return str(e)
  7. while True:
  8.     user_input = input("请输入一个表达式(输入'q'退出):")
  9.     if user_input.lower() == 'q':
  10.         break
  11.     print(f"结果是:{calculator(user_input)}")
复制代码

这个简易计算器展示了eval在交互式脚本中的价值,但它在生产环境只能用于完全可信的输入,否则存在严重安全漏洞。

七、实际应用:用exec动态修改对象属性
exec还可以根据配置代码批量修改对象属性,适合实现可扩展的配置逻辑:
  1. class MyClass:
  2.     def __init__(self):
  3.         self.attr1 = 1
  4.         self.attr2 = 2
  5. obj = MyClass()
  6. config_code = """
  7. obj.attr1 = 10
  8. obj.attr2 = 20
  9. """
  10. exec(config_code)
  11. print(f"attr1 的值是:{obj.attr1}")
  12. print(f"attr2 的值是:{obj.attr2}")
复制代码

最终输出attr1为10,attr2为20。这种方式适合将部分业务逻辑或策略以代码片段形式配置到脚本中,但同样需要限制代码来源。

总结
eval擅长求值表达式并返回结果,exec擅长执行多条语句并可以定义函数、类或修改对象状态。两者都可以通过globals和locals参数控制代码执行环境,从而避免直接污染当前作用域。使用动态执行能力能够显著提升程序的灵活性和可扩展性,但安全始终是前提。对于不信任的字符串,永远不要直接交给eval或exec去执行,否则就是把系统权限交给了攻击者。在充分理解风险并做好隔离的前提下,eval和exec才能成为Python脚本编程中可靠的工具。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-8 15:04 , Processed in 0.026956 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部