Python 如何执行字符串代码

430 阅读4分钟

你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益:

  1. 了解大厂经验
  2. 拥有和大厂相匹配的技术等

希望看什么,评论或者私信告诉我!

@TOC

一、前言

执行字符串类型的代码,是一种很常见的方式。对于 java8 来说,实现起来就比较麻烦,因为没有内置的,需要依赖三方的框架或者脚本语言。

最近在做 大模型 相关的项目,python 肯定是首选,而对于执行字符串类型的代码,python 就比 java 优雅的多,毕竟 python 是动态语言。

二、python 执行字符串代码

这里只关注 python 原生的,第三方库的,不关注。 在 Python 中,执行字符串形式的代码有几种方法,主要包括 exec()eval()。下面详细介绍这些方法及其用法。

2.1. exec()

exec() 函数用于执行包含 Python 代码的字符串。它可以执行多行代码。

示例:

code = """
def greet(name):
    return f"Hello, {name}!"

result = greet("Alice")
"""
# 执行代码
exec(code)

# 使用在 exec 中定义的函数
print(result)  # 输出: Hello, Alice!

2.2. eval()

eval() 函数用于执行一段单一的表达式,并返回表达式的结果。它适用于简单的计算或获取变量值。

示例

expression = "3 * 4 + 5"
result = eval(expression)
print(result)  # 输出: 17
x = 10
result = eval("x + 5")
print(result)  # 输出: 15

2.3. 使用 exec()eval() 的注意事项

  • 安全性:直接从不可信来源执行代码可能引入安全风险,应尽量避免。用户输入的字符串可能包含恶意代码。
  • 作用域exec()eval() 使用的作用域不同。你可以通过提供字典来控制变量作用域。

示例:使用自定义作用域

local_vars = {}
exec("y = 5", {}, local_vars)
print(local_vars['y'])  # 输出: 5

4. 总结

  • exec():用于执行多行代码,适合定义函数、类等复杂结构。
  • eval():用于计算单一表达式,返回其结果。

在使用这两种方法时,都要注意代码的安全性和可能的副作用。

三、更进一步,以 exec 为例

exec() 是 Python 的一个内置函数,用于动态执行 Python 代码。以下是它的原理及工作机制的详细说明:

3.1 原理

  1. 参数:

    • exec(object, globals=None, locals=None)
    • object: 要执行的代码,可以是字符串或代码对象。
    • globals: 一个可选的字典,用于指定全局命名空间。
    • locals: 一个可选的字典,用于指定局部命名空间。
  2. 代码编译:

    • exec() 首先将传入的代码字符串编译为字节码。这是通过调用 Python 的编译器实现的。
  3. 执行上下文:

    • 代码在指定的全局和局部命名空间中执行。若未提供,默认使用当前的命名空间。这允许动态定义和修改变量。
  4. 可动态创建功能:

    • exec() 可以创建函数、类及执行任意的 Python 语句,提供了强大的动态性。

3.2 示例

code = """
def greet(name):
    return f"Hello, {name}!"

result = greet("World")
"""

# 执行代码
exec(code)

# 输出结果
print(result)  # 输出: Hello, World!

关键特性

  • 命名空间: 通过 globalslocals 可以控制代码的执行环境。这意味着可以将特定变量传递给执行的代码。

  • 动态性: exec() 允许在运行时生成和执行代码,使其在反射和元编程时非常有用。

安全性和性能

  • 安全风险: 使用 exec() 执行来自不信任来源的代码会导致安全漏洞,因为攻击者可以注入恶意代码。

  • 性能开销: 动态编译和执行代码相较于静态导入和调用,性能较低,不应在性能敏感的场景中使用。

四、总结

本文主要讲解了Python中的exec()eval()函数,这两种函数可以执行字符串形式的代码。exec()用于执行多行代码,适用于定义函数、类等复杂结构;而eval()用于计算单一表达式,返回其结果。在使用这两种方法时,需要注意代码的安全性和可能的副作用,避免执行来自不可信来源的代码。