为什么 eval 找不到在外部函数中定义的变量?
Why can't eval find a variable defined in an outer function?
我知道使用 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()
中的局部变量,而 "used" 是什么东西?这是怎么回事?
简而言之,由于eval
是动态计算的,解释器无法知道它应该将a
添加到g
的本地范围。为了效率,解释器不会在局部变量的dict
中添加不需要的变量。
来自 eval
的文档:
The expression argument is parsed and evaluated as a Python expression (technically speaking, a condition list) using the globals and locals dictionaries as global and local namespace.
这意味着函数 eval(expression)
将使用 globals()
作为其默认全局范围,如果提供 none 则使用 locals()
作为其本地范围。
虽然,在你的第一个例子中 a
两者都不在。
def f(a):
print("f's locals:", locals())
def g():
print("g's locals:", locals())
print(eval('a'))
return g()
f(1)
确实,由于解释器在解析 g
的主体时没有看到对 a
的引用,因此不会将其添加到其局部变量中。
要使其正常工作,您需要在 g
中指定 nonlocal a
。
输出
f's locals: {'a': 1}
g's locals: {}
Traceback ...
...
NameError: name 'a' is not defined
在您的第二个示例中,a
在 g
局部变量中,因为它在范围内使用。
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
看起来 eval() 只能在本地(此处,g)或全局中查找变量,而不能在其父环境(此处为 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
我知道使用 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()
中的局部变量,而 "used" 是什么东西?这是怎么回事?
简而言之,由于eval
是动态计算的,解释器无法知道它应该将a
添加到g
的本地范围。为了效率,解释器不会在局部变量的dict
中添加不需要的变量。
来自 eval
的文档:
The expression argument is parsed and evaluated as a Python expression (technically speaking, a condition list) using the globals and locals dictionaries as global and local namespace.
这意味着函数 eval(expression)
将使用 globals()
作为其默认全局范围,如果提供 none 则使用 locals()
作为其本地范围。
虽然,在你的第一个例子中 a
两者都不在。
def f(a):
print("f's locals:", locals())
def g():
print("g's locals:", locals())
print(eval('a'))
return g()
f(1)
确实,由于解释器在解析 g
的主体时没有看到对 a
的引用,因此不会将其添加到其局部变量中。
要使其正常工作,您需要在 g
中指定 nonlocal a
。
输出
f's locals: {'a': 1}
g's locals: {}
Traceback ...
...
NameError: name 'a' is not defined
在您的第二个示例中,a
在 g
局部变量中,因为它在范围内使用。
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
看起来 eval() 只能在本地(此处,g)或全局中查找变量,而不能在其父环境(此处为 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