本地框架不能在其父框架中使用名称绑定

时间:2017-10-08 20:36:12

标签: python

在编程课程中遇到了python环境概念,并提出了以下问题。

例如:

(1)

>>>def f(x):
       def g(y):
           return x - y
        return g
>>> f(2)(3)
-1

(2)

def f(x):
    def g(y):
        x = x - y
        return x
    return g
>>> f(2)(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in g
UnboundLocalError: local variable 'x' referenced before assignment

(3)

>>> def f(x):
        def g(y):
            if x > y:
               x = x - y
            else:
               x = y - x
            return x
        return g
>>> f(2)(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in g
UnboundLocalError: local variable 'x' referenced before assignment

示例(1)可以从其父帧引用“x”,但是(2)和(3)不能。我无法弄清楚为什么。如果(2)由于赋值给非本地名称而失败,为什么(3)在第3行给出错误,而不是第4行?

1 个答案:

答案 0 :(得分:0)

每当你提到&#39;对于Python中的名称,您隐式执行非限定名称查找。这些遵循LEGB规则:系统在顺序中的不同位置查找名称的绑定

  1. 在执行查找的函数的 L ocal范围内(如果有)
  2. 在函数的本地范围 E 中关闭正在进行查找的那个(如果有的话)
  3. G 小册子
  4. B uiltins模块中。
  5. 一旦找到您寻找的名称的绑定,搜索就会停止。如果名称绑定在多个位置,则列表中较早的名称将被称为 shadow 后者。

    在您的第一个代码示例中,x绑定在 E / f中,y绑定在 L / { {1}}。两者都是函数的参数,函数参数绑定在函数的局部范围内。

    在您的第二个示例g中绑定内部函数x = L ocal范围中的名称x,从而阴影 g E 封闭函数x中的绑定。因此,LEGB不再在 E / f中找到x,而在 L / f中找到。{/ p>

    通过查看g内部编写的x = Python在编译时决定 g的绑定来自x。遗憾的是,在运行时尚未确定gx的绑定。这就是为什么你得到g

    在第三个示例中,出现了完全相同的问题:在第4行,编译器发现 L / UnboundLocalError中存在x的绑定,这会影响在 E / g中绑定x,因此fx的绑定将在运行时使用。在运行时,我们在第4行(名称被绑定)之前到达第3行(查找名称),所以再次g

    错误在第3行,因为这是查找失败的行。

    总之,在UnboundLocalError中分配x没有任何问题。当您尝试在g中查找x之前的值时,会出现此问题。

    如果你在Python 3中,你可以在内部函数g中添加声明nonlocal x。这意味着:亲爱的编译器,如果在此范围内的任何位置找到尝试绑定g的代码,请不要在范围内创建绑定,而是在任何封闭范围内重新绑定该名称已经提供了约束力。