在编程课程中遇到了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行?
答案 0 :(得分:0)
每当你提到&#39;对于Python中的名称,您隐式执行非限定名称查找。这些遵循LEGB规则:系统在顺序中的不同位置查找名称的绑定
一旦找到您寻找的名称的绑定,搜索就会停止。如果名称绑定在多个位置,则列表中较早的名称将被称为 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
。遗憾的是,在运行时尚未确定g
中x
的绑定。这就是为什么你得到g
。
在第三个示例中,出现了完全相同的问题:在第4行,编译器发现 L / UnboundLocalError
中存在x
的绑定,这会影响在 E / g
中绑定x
,因此f
中x
的绑定将在运行时使用。在运行时,我们在第4行(名称被绑定)之前到达第3行(查找名称),所以再次g
。
错误在第3行,因为这是查找失败的行。
总之,在UnboundLocalError
中分配x
没有任何问题。当您尝试在g
中查找x
之前的值时,会出现此问题。
如果你在Python 3中,你可以在内部函数g
中添加声明nonlocal x
。这意味着:亲爱的编译器,如果在此范围内的任何位置找到尝试绑定g
的代码,请不要在此范围内创建绑定,而是在任何封闭范围内重新绑定该名称已经提供了约束力。