为什么eval找不到外部函数中定义的变量?

时间:2018-09-12 15:15:42

标签: python eval local-variables

我知道使用eval()通常意味着错误的代码,但是我偶然发现我无法理解的内部函数中eval()函数的怪异行为。如果我们写:

def f(a):
    def g():
        print(eval('a'))
    return g()

在这种情况下运行f(1)会产生NameError,声称a未定义。但是,如果我们定义

def f(a):
    def g():
        b = a + 1
        print(eval('a'))
    return g()

然后运行f(1)将打印1

我不太了解局部变量和全局变量的情况。 a仅在g()中用于某些用途时是局部变量吗?这是怎么回事?

2 个答案:

答案 0 :(得分:4)

简而言之,由于eval用于动态求值,解释器无法知道应该将a添加到g的本地范围中。为了提高效率,解释器不会将不需要的变量添加到局部变量dict中。

来自eval的文档:

  

expression参数将使用globals和locals字典作为global和local名称空间解析并评估为Python表达式(从技术上来说是条件列表)。

这意味着函数eval(expression)将使用globals()作为其默认全局范围,而将locals()用作其本地范围(如果未提供)。

尽管,在您的第一个示例中,a都不存在。

def f(a):
    print("f's locals:", locals())
    def g():
        print("g's locals:", locals())
        print(eval('a'))
    return g()

f(1)

实际上,由于解释器在解析a的主体时看不到对g的引用,因此不会将其添加到其局部变量中。

要使其正常工作,您需要在nonlocal a中指定g

输出

f's locals: {'a': 1}
g's locals: {}
Traceback ...
...
NameError: name 'a' is not defined

在第二个示例中,ag局部变量中,因为它在范围中使用。

def f(a):
    print("f's locals:", locals())
    def g():
        print("g's locals:", locals())
        b = a + 1
        print("g's locals after b = a + 1:", locals())
        print(eval('a'))
    return g()

f(1)

输出

f's locals: {'a': 1}
g's locals: {'a': 1}
g's locals after b = a + 1: {'a': 1, 'b': 2}
1

答案 1 :(得分:0)

看起来eval()只能在local(here,g)或global中查找变量,而不能在其父环境(此处f)中查找。可以将变量设置为全局变量。

 
def f(a):    
    global b #note, can not use "global a" directly,  will get error:"name 'a' is parameter and global"
    b=a
    def g():
        print(eval('b'))
    return g()
f(1)

输出:1