【问题标题】:UnboundLocalError in python confusingpython中的UnboundLocalError令人困惑
【发布时间】:2012-09-22 07:00:08
【问题描述】:

谁能解释以下代码的异常。它仅在我将 display() 中的 var sub 更改为另一个名称时才有效。也没有全局变量 sub 。那么发生了什么?

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

【问题讨论】:

  • 最初,sub 是一个函数。然后,它成为函数的返回值。所以当你说print sub时,python不知道你指的是哪个sub
  • @inspectorG4dget:您的解释非常简单。谢谢

标签: python


【解决方案1】:

对于每个使用的变量,Python 都会确定它是局部变量还是非局部变量。引用未知变量将其标记为非本地变量。以后重用同名作为局部变量被认为是程序员的错误。

考虑这个例子:

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

这给了你

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 是来自外部范围(上值或全局)的变量。但是,在x = 3 中,x 用作局部变量。由于这是代码中的不一致,Python 提出了UnboundLocalError 以引起程序员的注意。

【讨论】:

    【解决方案2】:

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

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

    def a(): pass
    
    def b(): a = a()
    

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

    全局命名空间包含a 和b。

    函数a 不包含局部变量。

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

    def b(): x = x()
    

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

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

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

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

    【讨论】:

    • 所以未绑定的错误来自对函数的调用,因为它首先被先前的赋值遮蔽了?如果将x(局部变量)赋值给任何值,然后调用x(函数),是否一样?
    • 错误是您的函数包含对sub 的赋值,因此 sub 被视为局部变量。并且您尝试在初始分配期间使用此局部变量,而它还没有值。
    【解决方案3】:

    这原本是一条评论。 OP发现这作为一个有用的答案。因此,我将其重新发布为答案

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

    编辑:

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

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

    因此,如果您的语句是x = x+1,那么x 最好在该行之前为其分配一个值;并且之前定义的x 必须是与添加1 兼容的某种类型。

    但是假设 x 是一个函数,并且你在其他函数中创建了一个名为 x 的变量,并尝试为其分配一个使用函数 x 计算的值,那么这真的开始让 python 感到困惑您指的是x。这确实是对this answer 的过度简化,它在解释 Python 函数中的变量范围和阴影方面做得更好

    【讨论】:

    • 这被过度简化了——如果你在display 中说sub = 1,你仍然会隐藏函数名,这是完全合法的。问题是名称在同一范围内使用和分配给。有关 python 中闭包的更详细说明,请参阅this answer。
    • @l4mpi:很公平。我真的应该在星期一早上喝咖啡之前停止回答问题。谢谢你的澄清
    【解决方案4】:

    Python 开始执行你的代码并首先获取函数

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

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

    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 变量。所以它会产生问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-17
      • 2013-08-23
      • 1970-01-01
      • 2022-01-21
      • 2022-01-17
      • 2018-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多