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

为何eval('bar')触发NameError,添加print(bar)后却无报错?

嵌套作用域中eval访问变量的问题解析

问题复现

触发NameError的代码

def foo():
    def bar():
        return 'blah'
    def baz():
        eval('bar')
    baz()
foo()

完整报错信息

Traceback (most recent call last):
  File "main.py", line 7, in <module>
    foo()
  File "main.py", line 6, in foo
    baz()
  File "main.py", line 5, in baz
    eval('bar')
  File "<string>", line 1, in <module>
NameError: name 'bar' is not defined

无错误的代码

def foo():
    def bar():
        return 'blah'
    def baz():
        print(bar); eval('bar')
    baz()
foo()

这段代码会打印类似 <function foo.<locals>.bar at 0x7fd5fdb24af0> 的内容,且不会触发任何报错。

问题解答

第一段代码为何无法访问bar?

这是Python静态作用域解析机制和eval特性共同作用的结果:

  • Python编译函数baz时,会扫描函数内的变量引用。第一段代码里,baz内部没有直接写bar的引用,只有eval的字符串参数里提到了bar——编译阶段无法解析字符串内容,所以Python不会把bar标记为需要从外层foo作用域查找的变量。
  • 当eval执行时,默认使用当前baz的局部作用域查找变量,但baz自身没定义bar,也没有关联外层的bar,因此抛出NameError。

提前执行print(bar)为何能解决问题?

当baz里加入print(bar)后,Python编译baz时会直接扫描到对bar的显式引用,此时会把bar标记为自由变量,即需要从外层嵌套的foo作用域中查找。

  • 后续eval执行时,baz的作用域已经关联了外层的bar变量,自然就能找到它。

本质原因

这不是eval的bug,而是Python的静态作用域规则决定的:变量的查找路径在编译阶段就确定了,eval的字符串参数属于动态内容,编译阶段无法识别其中的变量引用,也就不会为其建立外层作用域的查找关联。只有显式的变量引用,才会让Python在编译时标记为自由变量,让后续动态执行(比如eval)能找到对应变量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 19:55:22