python中的UnboundLocalError令人困惑

UnboundLocalError in python confusing

有人能解释一下下面的例外代码吗?仅当我将display()中的var sub更改为其他名称时,它才起作用。也没有全局变量Sub。那发生了什么?

1
2
3
4
5
6
def sub(a, b):
    return a - b

def display():
    sub = sub(2,1) // if change to sub1 or sth different to sub, it works
    print sub


您在作用域内分配给的任何变量都被视为局部变量(除非您声明为global,或者在python3中声明为nonlocal,这意味着它不在周围作用域中查找。

具有相同错误的简化示例:

1
2
3
def a(): pass

def b(): a = a()

现在,考虑这里涉及的不同范围:

全局命名空间包含ab

函数a不包含局部变量。

函数b包含对a的赋值,这意味着它被解释为局部变量,并从外部作用域(在本例中为全局作用域)隐藏函数a。由于调用前b内部没有定义a,因此它是未绑定的局部变量,因此是未绑定的局部错误。这和你写的一样:

1
def b(): x = x()

解决方法很简单:为sub调用的结果选择不同的名称。

重要的是要注意,使用和分配的顺序没有区别-如果您这样编写函数,错误仍然会发生:

1
2
3
4
def display():
    value = sub(2,1)         #UnboundLocalError here...
    print value
    sub ="someOtherValue"   #because you assign a variable named `sub` here

这是因为局部变量列表是在Python解释器创建函数对象时生成的。


对于使用的每个变量,python都确定它是局部变量还是非局部变量。引用未知变量将其标记为非局部变量。稍后重用与局部变量相同的名称被认为是程序员的错误。

考虑这个例子:

1
2
3
4
def err():
    print x # this line references x
    x = 3   # this line creates a local variable x
err()

这给了你

1
2
3
4
5
6
Traceback (most recent call last):
  File"asd.py", line 5, in <module>
    err()
  File"asd.py", line 2, in err
    print x # this line references x
UnboundLocalError: local variable 'x' referenced before assignment

实际上,python跟踪代码中所有对名称的引用。当它读取行print x时,python知道x是来自外部作用域(upvalue或global)的变量。然而,在x = 3中,x用作局部变量。由于这是代码中的不一致性,所以python提出了一个UnboundLocalError,以引起程序员的注意。


这最初是一个评论。OP发现这是一个有用的答案。因此,我重新发布它作为答案

最初,sub是一个函数。然后,它成为函数的返回值。所以当你说print sub时,python不知道你指的是哪个sub

编辑:

首先定义一个函数sub。现在,python知道了sub是什么。

当您创建一个变量并试图分配给它时(比如x = 2,python会对=右侧的内容进行评估,并将评估的值分配为=左侧的内容的值。因此,右侧的所有内容都应该进行实际计算。

因此,如果您的声明是x = x+1,那么x最好在该行之前分配一个值;之前定义的x必须是与1的添加兼容的类型。

但是假设x是一个函数,在其他函数中生成一个名为x的变量,并试图将一个用函数x计算的值赋给它,那么这真的开始混淆您所指的x是什么。这确实是对这个答案的过度简化,它在解释变量范围和在python函数中隐藏方面做得更好。


python开始执行代码并首先获取函数

1
2
def sub(a, b):
    return a - b

所以在执行这个解释器之后,将sub作为一个函数。现在到下一行的时候它发现了

1
2
3
def display():
    sub = sub(2,1) // if change to sub1 or sth different to sub, it works
    print sub

所以第一行sub = sub (2, 1)sub函数转换为sub变量。从这个函数返回sub变量。所以这就产生了问题。