不带参数输入的函数变量范围

问题描述:

我想了解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()是definid。之后,我运行function_a(),其中A被赋值为1.

因此在function_a()的范围内存在变量A = 1。

然后function_b()被调用并打算打印变量A的值。 A不存在于function_b()的作用域中。因此,我认为它会看起来更高,这将是function_a()的范围,因为function_b()function_a()内运行。

但很明显,我错了。究竟发生了什么?

+2

虽然它不是_directly_有关这个问题,我怀疑你会发现这篇文章有帮助:关于Python的名称和值事实与神话(http://nedbatchelder.com/text/names.html) ,这是由SO老将Ned Batchelder写的。 –

只是因为你有叫function_bfunction_a内并不意味着我t会继承function_a的范围,并有充分的理由。该函数从它定义的地方获取范围,而不是它被调用的地方。

如果您想完成类似closures的操作,您应该尝试在function_a的内部定义function_b

def function_a(A): 
    def function_b(): 
     print(A) 

就这样说,我并没有真正看到这里的封闭用例。您最好将变量作为参数传递。这样它会更加可重用和可测试。

def function_a(A): 
    function_b(A) 

def function_b(A): 
    print(A) 

因此,我希望它看起来级别更高,因为function_b()是内 function_a()

它看起来更高版本上运行这将是function_a()的 范围。但function_a的范围不高于function_b的范围。范围有些独立。不要将范围层次与堆栈框架混淆。层次结构中的下一个范围是模块范围,这里是全局范围; A不在全球范围内。

要访问function_b中的A,您可以将其作为参数传递给function_b或在模块范围中定义A

+1

Upvoted,但我认为你应该考虑用一种对新手更容易理解的方式来描述它 - IMO在这里有太多技术术语(“范围层级”,“堆栈框架”),当你可以表达相同的通过说“像函数的作用域取决于它的位置_defined_,而不是它被调用的位置”这样一种更清晰的方式。 –

+0

@Rawing感谢您的反馈。我想这就是接受的答案,而且很可能是为什么它被接受。学习...... –

+0

作为提问者,我可以证实这确实是我接受@ hspandher的答案的原因。我也提出了你的回答,因为它确实回答了这个问题。我只是认为另一个答案说得更清楚一些,说'函数从定义的范围获取范围,而不是它被调用的地方'。 感谢您的回答,虽然 – elevendollar

会发生什么事是,在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因为查找将成功打印的结果。

我假设发生这种情况是因为python没有将绑定参数放置在变量绑定接收的同一个命名空间中。参数绑定仅存在于函数的范围内。

正确的方法实现的是使用python关闭您的影响(其包围他们的父母函数的命名空间):

def function_a(A): 
    def function_b(): 
     print(A) 

    function_b() 

function_a(1) 

您可能值A简单地传递给这两种功能,但这可能会建议你做含A类(特别是如果A是由许多功能要求):

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()