我试图理解Python(3.x)中的变量范围,但下面是一个代码不能工作的例子,我不知道为什么。
def function_a(A):
function_b()
def function_b():
print(A)
function_a(1)
导致NameError: name 'A' is not defined
所以,我认为它的工作方式是function_a()
和function_b()
是明确的。然后我运行function_a()
,其中A
被赋值为1.
因此,在function_a()
的范围内,变量A = 1存在。
然后调用function_b()
并打算打印变量A
的值。在function_b()的范围内不存在A.因此,我希望它看起来更高,这是function_a()
的范围,因为function_b()
在function_a()
内运行。
但显然,我错了。实际发生了什么?
答案 0 :(得分:6)
仅仅因为你在function_b
内调用function_a
并不意味着它会继承function_a
的范围并且有充分的理由。该函数从其定义的范围获取范围,而不是它被调用的位置。
如果你想完成像closures
这样的事情,你应该尝试在function_b
内定义function_a
。
def function_a(A):
def function_b():
print(A)
话虽如此,我还没有真正看到一个关闭用例。你最好将变量作为参数传递。这样,它将更具可重用性和可测试性。
def function_a(A):
function_b(A)
def function_b(A):
print(A)
答案 1 :(得分:3)
因此我希望它看起来更高,这将是 范围
function_a()
因为function_b()
在其中运行function_a()
确实看起来更高。但function_a
的范围并不高于function_b
的范围。范围有些独立。不要将作用域层次结构与堆栈帧混淆。层次结构中的下一个范围是模块范围,这里是全局范围; A
不在全球范围内。
要访问A
中的function_b
,您可以将其作为参数传递给function_b
或在模块范围内定义A
。
答案 2 :(得分:1)
在function_b
中,全局范围内的搜索已完成,并且由于全局范围未定义名称A
并且不存在封闭的函数范围,因此您将获得NameError
。
如果存在封闭范围:
def function_a(A):
def function_b():
print(A)
function_b()
function_a(1) # prints 1
或者定义了全局名称A
:
A = 2
def function_a(A):
function_b()
def function_b():
print(A)
function_a(1) # prints 2 (finds global name A)
您将获得A
打印的结果,因为查找会成功。
答案 3 :(得分:0)
我认为这是因为python没有将绑定放在变量绑定接收的同一命名空间中的参数。参数绑定仅存在于函数的范围内。
实现效果的正确方法是使用python闭包(它包含其父函数的命名空间):
def function_a(A):
def function_b():
print(A)
function_b()
function_a(1)
您可以简单地将值A
传递给两个函数,但这可能表明您应该创建一个包含A
的类(特别是如果许多函数需要A
):< / p>
class A(object):
def __init___(self, a):
self.a = a
def function_a(self):
self.function_b()
def function_b(self):
print(self.a)
foo = A(1)
foo.function_a()