本地帧无法使用其父帧中绑定的名称。

12 浏览
0 Comments

本地帧无法使用其父帧中绑定的名称。

在一门编程课程中遇到了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 "", line 1, in 
  File "", 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 "", line 1, in 
  File "", line 3, in g
UnboundLocalError: local variable 'x' referenced before assignment

例子(1)可以从其父级框架引用 'x',但(2)和(3)不能。我无法弄清楚为什么。如果(2)因为给非局部名称赋值而失败,为什么(3)在第3行而不是第4行出错?

0
0 Comments

在Python中,当你引用一个名字时,你实际上是在执行一个未限定的名字查找。这遵循LEGB规则:系统按照以下顺序在不同的位置查找名字的绑定:

1. 在查找所在函数的局部作用域中(如果有的话)

2. 在查找所在函数的闭包中的局部作用域中(如果有的话)

3. 在全局作用域中

4. 在内置模块中

只要找到所需名字的绑定,搜索就会停止。如果名字在这些位置中的多个位置都有绑定,那么列表中较早的绑定会“遮蔽”较后的绑定。

在第一个代码示例中,x在E/f中绑定,y在L/g中绑定。它们都是函数的参数,函数参数在函数的局部作用域中绑定。

在第二个示例中,x = 在内部函数g的局部作用域中绑定了名字x,从而遮蔽了外部函数f中x的绑定。因此,LEGB不再在E/f中找到x,而是在L/g中找到x。

通过在g中看到x =,Python在编译时决定x的绑定来自g。不幸的是,在运行时,g中的x的绑定尚未建立。这就是为什么会出现UnboundLocalError的原因。

在第三个示例中,发生了完全相同的问题:在第4行,编译器发现在L/g中有x的绑定,它遮蔽了E/f中x的绑定,因此将在运行时使用g中x的绑定。在运行时,在第3行(查找名称的行)之前到达第4行(绑定名称的行),因此再次出现UnboundLocalError。

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

总之,在g中赋值给x没有问题。问题出现在尝试在g中查找x的值之前。

如果你在Python 3中,你可以在内部函数g中添加声明nonlocal x。这意味着:亲爱的编译器,在这个作用域中的任何地方,如果你发现有尝试绑定x的代码,请不要在这个作用域中创建一个绑定,而是在已经提供绑定的任何封闭作用域中重新绑定该名称。

在运行时,赋值语句的右手边必须在左手边绑定之前被求值:在计算出值之前,它怎么能被绑定呢!在这种情况下,说编译器从左到右工作并不是很有意义。重要的是,编译器在运行时之前分析代码的结构。在你最后一句中,你的说法不完全正确:编译器不会绑定x,而是决定x在哪里被绑定。然后,在运行时发生查找操作之前进行绑定。

顺便说一句,如果你认为这个回答是好的,你应该点赞它。如果你认为它解决了你的问题,那么你应该接受它。

0