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

如何在Python库函数的eval()中调用外部定义的函数?

问题:adv_prod函数无法识别外部自定义函数

问题重现

我开发的PyPI库中有一个使用eval()的adv_prod函数:

def adv_prod(start,end,rule):
    ending_seq = list_prod([eval(rule) for i in range(start,end+1)])
    return ending_seq

当传入库内定义的函数(如同一文件中的prime(i))时可以正常运行:

from supMath import adv_prod,prime

for x in range(1,11):
    print(adv_prod(1,x,"prime(i)")) 

输出:

2
6
30
210
2310
30030
510510
9699690
223092870
6469693230

但传入外部自定义函数时会触发NameError:

from supMath import adv_prod

def fib(n):
    if n==1:
        return 1
    if n==2:
        return 1
    return fib(n-2)+fib(n-1)

for x in range(1,11):
    print(adv_prod(1,x,"fib(i)")) 

输出:

NameError: name 'fib' is not defined

原因分析

eval()默认在adv_prod函数的局部作用域中执行代码,外部自定义函数fib不在这个作用域内,所以无法被识别。而库内的prime函数属于adv_prod所在模块的全局作用域,因此可以被找到。

解决方案

方案1:传递函数对象(推荐,安全且简洁)

修改adv_prod,让它直接接收函数对象而非字符串规则,彻底避免eval()的安全风险和作用域问题:

def adv_prod(start, end, rule_func):
    # 直接调用传入的函数,传入i作为参数
    ending_seq = list_prod([rule_func(i) for i in range(start, end+1)])
    return ending_seq

调用方式改为直接传入函数名:

from supMath import adv_prod

def fib(n):
    if n==1:
        return 1
    if n==2:
        return 1
    return fib(n-2)+fib(n-1)

for x in range(1,11):
    print(adv_prod(1,x,fib))  # 直接传fib函数对象

方案2:传递作用域给eval(不推荐,存在安全风险)

如果必须保留字符串规则的调用方式,可以让eval()访问调用者的作用域,以下是两种实现方式:

方式A:显式传递作用域参数

修改adv_prod,允许传入调用者的全局/局部变量:

def adv_prod(start, end, rule, globals=None, locals=None):
    ending_seq = list_prod([eval(rule, globals, locals) for i in range(start, end+1)])
    return ending_seq

调用时传入当前作用域:

from supMath import adv_prod

def fib(n):
    if n==1:
        return 1
    if n==2:
        return 1
    return fib(n-2)+fib(n-1)

for x in range(1,11):
    print(adv_prod(1,x,"fib(i)", globals(), locals()))

方式B:自动获取调用者作用域(依赖inspect)

使用inspect模块获取调用者的栈帧,从而拿到其作用域:

import inspect

def adv_prod(start, end, rule):
    # 获取调用者的栈帧
    caller_frame = inspect.currentframe().f_back
    try:
        # 使用调用者的全局和局部作用域执行eval
        ending_seq = list_prod([eval(rule, caller_frame.f_globals, caller_frame.f_locals) for i in range(start, end+1)])
    finally:
        # 手动删除栈帧引用,避免内存泄漏
        del caller_frame
    return ending_seq

调用方式和原来一致:

from supMath import adv_prod

def fib(n):
    if n==1:
        return 1
    if n==2:
        return 1
    return fib(n-2)+fib(n-1)

for x in range(1,11):
    print(adv_prod(1,x,"fib(i)"))

注意:这种方式依赖Python的栈帧实现,可能在某些优化环境中失效,且eval()执行外部传入的字符串存在代码注入风险,不建议在公开库中使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 14:37:19