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

Python函数内exec创建动态变量 循环/列表推导式报NameError

问题根因

该错误由Python函数内部的作用域编译规则导致,核心逻辑如下:

  • Python在编译函数阶段就会静态扫描函数体内所有直接引用、直接赋值的变量,将其标记为局部变量,这类变量的查找逻辑在编译期就已绑定,不会在运行时动态检索局部命名空间字典。
  • 函数内调用exec()执行赋值语句时,如果不手动指定命名空间参数,exec()内创建的变量会被写入locals()返回的局部字典——这就是你调用dir()能看到f1/f2/f3存在的原因。
  • 但编译阶段生成的局部变量查找逻辑,不会主动读取运行时才被exec()塞进局部字典的变量。你在代码中直接写f1.predict()、f.append(2)时,解释器在静态扫描阶段没找到这些变量的定义,执行时就会直接抛出NameError,不会去局部字典里动态查找。
  • 交互环境逐行执行、函数外(模块全局作用域)执行不报错的原因是:全局作用域的变量查找本身就是动态检索globals()字典的,exec()在全局作用域创建的变量会直接进入全局字典,后续引用可以被正常查到。
复现逻辑验证

你提供的最小测试用例完全符合上述规则:

def test():
    exec("f= []")
    f.append(2)
    print(f)

if __name__=="__main__":
    test()

执行该脚本必然抛出NameError: name 'f' is not defined,哪怕在exec语句后加print(locals())能明确看到f存在于局部字典中,直接引用依然会报错。

推荐修复方式

不要使用exec()动态注入局部变量,改用字典显式管理加载的模型,逻辑清晰且无作用域问题:

import pickle

def predict(new_data):
    model_list = fetch_needed_models() # ["f1","f2","f3"]
    loaded_models = {}
    for model_name in model_list:
        with open(f"./{model_name}.pkl", "rb") as file:
            loaded_models[model_name] = pickle.load(file)
    
    # 调用时直接从字典取对应模型
    f1_pred = [loaded_models["f1"].predict(x) for x in new_data]

不推荐的变通方案:提前在函数内初始化对应变量、或声明变量为global/nonlocal骗过编译器静态检查,这类写法可维护性极差,极易引入隐蔽bug。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 20:36:25