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

为何Python的exec()执行含列表推导式的字符串代码时会报NameError?

列表推导式在exec中报NameError的原因

这个问题是三个机制共同作用的结果:

  • Python3中所有列表/集合/字典推导式、生成器表达式,都会在底层创建一个独立的隐式函数作用域,和外层代码隔离开。普通for循环不会新建作用域,循环内代码和外层代码共用同一个变量表,而推导式找变量要严格遵循LEGB作用域查找规则:先查自己的本地变量,再查外层闭包绑定的变量,再查全局变量,最后查内置变量。
  • 闭包的外层变量绑定是代码编译阶段就静态确定的,不会识别运行时动态插入的变量。
  • 你在unittest的测试函数/测试方法里调用exec(cell.source)时,没有显式指定命名空间,此时exec()会默认把执行过程中定义的变量(比如你这里的pattern)动态写入当前测试函数的locals()字典。但这些动态插入的变量不在编译期确定的闭包绑定列表里,推导式生成的隐式函数根本找不到它,就会抛出NameError。

你换成普通for循环能正常运行,本质是因为for循环不新建作用域,循环代码直接在exec的执行上下文里读本地变量表,能拿到动态写入的pattern。而Jupyter Notebook的单元格是在模块全局作用域执行的,模块级的locals()和globals()是同一个字典,exec动态写入的变量直接进全局命名空间,推导式查全局作用域时能找到pattern,所以不会报错。

修复方法

调用exec时显式传入一个独立的命名空间字典作为全局命名空间,让所有执行代码的变量都落在这个全局字典里,推导式就能正常查到变量了:

# 预先把测试需要的前置变量放进命名空间
exec_namespace = {"y": y}
exec(cell.source, exec_namespace)

# 后续校验直接从命名空间取变量即可
assert "pattern" in exec_namespace
assert "z" in exec_namespace

这种写法不管学生用列表推导式还是普通for循环,都能正常执行,不会出现作用域找不到变量的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 23:18:18