【问题标题】:Variable scope of function without parameter input无参数输入的可变功能范围
【发布时间】:2017-10-04 08:18:25
【问题描述】:

我试图理解 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 的值。 A 不存在于 function_b() 的范围内。因此,我希望它看起来更高,这将是function_a() 的范围,因为function_b()function_a() 中运行。

但很明显,我弄错了。实际发生了什么?

【问题讨论】:

标签: python python-3.x function scope


【解决方案1】:

仅仅因为您在function_a 内部调用了function_b,并不意味着它会继承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)

【讨论】:

    【解决方案2】:

    因此,我希望它看起来更高,这将是 function_a() 的范围,因为 function_b() 在其中运行 function_a()

    确实看起来更高。但是function_a的范围并不高于function_b的范围。范围有些独立。不要将作用域层次结构与堆栈框架混淆。层次结构中的下一个作用域是模块作用域,这里是全局作用域; A 不在全局范围内。

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

    【讨论】:

    • 赞成,但我认为你应该考虑以一种更容易让新手理解的方式措辞 - IMO 这里有太多的技术术语(“范围界定层次结构”,“堆栈框架”),当您可以通过说“函数的范围取决于它在哪里定义,而不是它在哪里调用”这样的话,以更清晰的方式表达同样的事情。
    • @Rawing 感谢您的反馈。我想这就是接受的答案所做的,而且很可能是它被接受的原因。学习...
    • 作为提出这个问题的人,我可以确认这确实是我接受@hspandher 答案的原因。不过,我也赞成您的回答,因为它确实回答了这个问题。我只是认为另一个答案通过说“函数从定义它的位置而不是调用它的位置获取范围”使其更加清晰。不过谢谢你的回答
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      我认为这是因为 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()
      

      【讨论】:

        猜你喜欢
        • 2019-05-12
        • 2019-06-18
        • 2011-03-14
        • 2015-10-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多