You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中如何获取exec()定义的可调用函数?求通用正确方法

问题描述

我想要实现一个exec_myfunc函数,能够执行任意用户以字符串形式定义的函数,并传入输入值10。用户定义的函数示例如下:

func1_str = """
def myfunc1(x):
    return x
"""

func2_str = """
def myfunc2(x):
    return x**2
"""

我目前用了一种不太规范的方法:通过正则表达式提取def和(之间的函数名,实现代码如下:

def exec_myfunc(func_str: str):

    import re
    exec(func_str)
    myfunc_str = re.search(r'def(.*)\(', func_str).group(1).strip()
    return eval(myfunc_str)(10)

print(exec_myfunc(func1_str))
# 10
print(exec_myfunc(func2_str))
# 100

请问实现该需求的通用且正确的方法是什么?

通用且正确的实现方法

方法1:使用自定义命名空间执行exec

直接利用exec的命名空间参数捕获定义的函数,既不会污染全局命名空间,也无需依赖正则匹配:

def exec_myfunc(func_str: str):
    namespace = {}
    exec(func_str, namespace)
    # 假设输入字符串只定义了一个函数,提取唯一的可调用对象
    func = next(v for v in namespace.values() if callable(v))
    return func(10)

# 测试示例
func1_str = """
def myfunc1(x):
    return x
"""
func2_str = """
def myfunc2(x):
    return x**2
"""
print(exec_myfunc(func1_str))  # 输出10
print(exec_myfunc(func2_str))  # 输出100

这种方法的优势:

  • 隔离执行环境,避免污染全局变量,安全性更高
  • 无需依赖字符串格式,能兼容各种合法的函数定义写法
  • 直接获取函数对象,逻辑清晰可靠

如果需要支持多函数定义但指定执行目标,可以约定固定函数名(比如myfunc),直接从命名空间中取值:

def exec_myfunc(func_str: str):
    namespace = {}
    exec(func_str, namespace)
    return namespace['myfunc'](10)

# 用户需按约定定义名为myfunc的函数
func_str = """
def myfunc(x):
    return x*3
"""
print(exec_myfunc(func_str))  # 输出30

方法2:用AST模块解析(严谨性拉满)

如果需要严格校验输入代码的合法性,或者处理更复杂的函数定义场景,使用Python内置的ast模块解析代码语法树是最优解:

import ast

def exec_myfunc(func_str: str):
    tree = ast.parse(func_str)
    # 遍历语法树,筛选出所有函数定义节点
    funcs = [node for node in ast.walk(tree) if isinstance(node, ast.FunctionDef)]
    if not funcs:
        raise ValueError("输入字符串中未定义任何函数")
    # 取第一个函数定义,编译并执行
    func_def = funcs[0]
    code = compile(ast.Module(body=[func_def], type_ignores=[]), filename="<ast>", mode="exec")
    namespace = {}
    exec(code, namespace)
    return namespace[func_def.name](10)

# 测试
print(exec_myfunc(func1_str))  # 输出10
print(exec_myfunc(func2_str))  # 输出100

该方法的核心优势:

  • 能精准识别合法的函数定义,自动过滤无效代码或语法错误
  • 完全规避正则匹配的各种边缘场景(比如带注释、装饰器的函数)
  • 可扩展性强,能进一步处理函数参数校验、装饰器解析等需求

原方法的问题

原正则提取的方式存在诸多缺陷:

  • 无法处理带括号注释的函数定义(比如def func(x): # 这是(测试)),会匹配到错误内容
  • 对函数定义的格式依赖极强,稍有变化(比如多行定义、带装饰器)就会失效
  • 使用全局exec和eval会污染全局命名空间,还存在潜在的安全风险

内容的提问来源于stack exchange,提问作者Shaun Han

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 15:10:29