【问题标题】:python: how binding workspython:绑定是如何工作的
【发布时间】:2011-05-16 14:12:38
【问题描述】:

我试图了解,python 中的变量绑定究竟是如何工作的。让我们看看这个:

def foo(x):
    def bar():
        print y
    return bar

y = 5
bar = foo(2)
bar()

这打印出 5,这在我看来是合理的。

def foo(x):
    def bar():
        print x
    return bar
x = 5
bar = foo(2)
bar()

这会打印 2,这很奇怪。在第一个示例中,python 在执行期间查找变量,第二个示例在创建方法时查找。为什么会这样?

明确一点:这非常酷,并且完全按照我的意愿工作。但是,我对内部 bar 函数如何获取其上下文感到困惑。我想了解幕后发生的事情。

编辑

我知道,局部变量具有更高的优先级。我很好奇,python 在执行过程中如何知道从我之前调用的函数中获取参数。 bar 是在 foo 中创建的,而 x 不再存在。它在创建函数时已将此x 绑定到参数值?

【问题讨论】:

    标签: python closures nested-function


    【解决方案1】:

    第二个示例实现了所谓的closure。函数bar 正在从其周围的上下文中引用变量x,即函数foo。这在对全局变量 x 的引用之前。

    另请参阅此问题Can you explain closures (as they relate to Python)?

    【讨论】:

    • 链接解释得很好。非常感谢。
    【解决方案2】:

    您提到的问题是 python 中变量的词法与动态范围之一。明确地说,python 定义了以下四个作用域。

    1. 首先搜索的最内层范围包含本地名称
    2. 从最近的封闭范围开始搜索的任何封闭函数的范围包含非本地名称,但也包含非全局名称
    3. 倒数第二个作用域包含当前模块的全局名称
    4. 最外层范围(最后搜索)是包含内置名称的命名空间

    在第一个示例中,“y”定义在函数栏之外,python 搜索最里面的范围并向上移动,直到在模块中找到全局变量“y”

    在第二个示例中,“x”由函数 foo(x) 定义,当 x 在 bar 内打印时,它属于封闭函数的范围。纯粹而言,已经定义了一个闭包。

    为了进一步研究 python 中的作用域,我发现以下article 非常适合阅读

    【讨论】:

      【解决方案3】:

      在这两个示例中,查找都是在运行时进行的。唯一的区别是有一个本地定义的变量x,而没有一个本地定义的变量y

      执行时...

      def foo(x):
          def bar():
              print y
      
          return bar
      
      y = 5
      bar = foo(2)
      bar()
      

      ...print 语句查找名为 y 的变量,并且只在全局上下文中找到它,因此它使用那个变量并打印“5”。

      在...

      def foo(x):
          def bar():
              print x
      
          return bar
      
      x = 5
      bar = foo(2)
      bar()
      

      ...当查找发生时,定义了一个作用域变量x——当调用foo 函数时,该变量固定为“5”。

      关键是参数在传递给函数时进行评估,因此外部函数foo 在调用时评估传入的参数。这有效地在foo 函数的上下文中创建了一个名为x 的变量,因此每当bar 执行时,它都会看到该变量,而不是全局定义的变量。

      这有时会令人困惑,如以下代码所示:

      lst = []
      for i in range(5):
          x = i
          lst.append(lambda: x)
      
      for func in lst:
          print func()  # prints 4 4 4 4 4
      

      你需要做的:

      lst = []
      for i in range(5):
          def _func(x):
              return lambda: x
      
          lst.append(_func(i))
      
      for func in lst:
          print func()  # prints 0 1 2 3 4
      

      【讨论】:

        【解决方案4】:

        没什么奇怪的,这是因为函数参数中的“x”比全局变量“x”具有更高的优先级。

        一开始,全局变量是个大恶。

        Python 有运算符“global”:

        >>> def foo(x):
        ...     def bar():
        ...          global x
        ...          print x
        ...     return bar
        ... 
        >>> x = 5
        >>> bar = foo(2)
        >>> bar()
        5
        

        【讨论】:

          【解决方案5】:

          它是作用域,第二个例子使用局部作用域变量x,在上面全局声明之前

          【讨论】:

            猜你喜欢
            • 2012-04-29
            • 1970-01-01
            • 2011-05-06
            • 2012-11-16
            • 2012-04-10
            • 2019-01-12
            • 2017-02-24
            • 2010-09-24
            • 2012-09-09
            相关资源
            最近更新 更多