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

在闭包中使用eval触发NameError的问题与解决方案

问题

全局环境下这段代码可以正常执行:

a = 1
fn = eval('lambda: a')
fn()

但把代码放到函数闭包内后,会抛出NameError:

def x():
    a = 1
    fn = eval('lambda: a')
    fn()
x()

报错信息:

NameError: name 'a' is not defined
解决方案

你已经找到的有效方法是给eval显式传入当前函数的局部命名空间:

def x():
    a = 1
    fn = eval('lambda: a', locals())
    fn()
x()

这个方案不会引入全局变量的副作用,是最贴合需求的解决方式。

为什么闭包场景下会有差异?

1. eval的默认命名空间规则

在全局作用域中,locals()和globals()指向同一个字典,eval默认会使用这个全局字典作为查找变量的命名空间,所以lambda能找到全局的a。
但在函数内部,eval默认只使用全局命名空间(即globals()的内容),不会自动去扫描当前函数的局部变量——因为函数的局部变量是存在栈帧的专用内存结构里,不是普通的可遍历字典,默认情况下eval不会去访问这部分内容。

2. 闭包变量的捕获逻辑

普通嵌套函数(直接写在代码里的lambda或def)会通过Python的闭包机制自动捕获外层函数的局部变量,这些变量会被保存在函数对象的__closure__属性中。但eval动态生成lambda时,如果你不指定局部命名空间,它只会绑定全局命名空间,不会触发闭包的变量捕获逻辑,所以运行lambda时只会在全局找a,自然找不到函数内的局部变量。

当你显式传入locals()给eval时,相当于强制让它在当前函数的局部命名空间中查找变量,此时生成的lambda就能正确绑定到函数内的a。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 22:33:28