具有嵌套函数作用域的UnboundLocalError

时间:2010-04-09 17:25:12

标签: python function

我有这样的代码(简化):

def outer():
    ctr = 0

    def inner():
        ctr += 1

    inner()

ctr会导致错误:

Traceback (most recent call last):
  File "foo.py", line 9, in <module>
    outer()
  File "foo.py", line 7, in outer
    inner()
  File "foo.py", line 5, in inner
    ctr += 1
UnboundLocalError: local variable 'ctr' referenced before assignment

我该如何解决这个问题?我认为嵌套的范围可以让我这样做。我试过'全球',但它仍然无效。

4 个答案:

答案 0 :(得分:32)

如果您使用的是Python 3,则可以使用nonlocal语句启用非本地名称的重新绑定:

def outer():
    ctr = 0

    def inner():
        nonlocal ctr
        ctr += 1

    inner()

如果您使用的是没有nonlocal的Python 2,则需要在没有裸名称重新绑定的情况下执行递增(通过将计数器保留为某个裸名称的项目或属性,不< / strong>作为一个裸名称本身)。例如:

...
ctr = [0]

def inner():
    ctr[0] += 1
...

,当然,无论您在其他地方使用裸ctr[0],都可以使用ctr

答案 1 :(得分:6)

来自http://www.devshed.com/c/a/Python/Nested-Functions-in-Python/1/

  

嵌套函数体中的代码可能   访问(但不重新绑定)本地   外部函数的变量也是   称为嵌套的自由变量   功能

因此,您需要明确地将ctr传递给inner

答案 2 :(得分:6)

说明

每当将值分配给函数内部的变量时,python都会将该变量视为该函数的局部变量。由于语句ctr += 1包含对ctr的赋值,因此python认为ctrinner函数的局部变量。因此,它甚至从不尝试查看在ctr中定义的outer变量的值。 python看到的本质上是这样的:

def inner():
    ctr = ctr + 1

我想我们都可以同意该代码会导致错误,因为ctr在定义之前就已被访问。

(有关Python如何确定变量范围的更多信息,另请参见this question。)

解决方案(在python 3中)

Python 3引入了nonlocal statement,其工作原理与global语句非常相似,但是允许我们访问周围函数的变量(而不是全局变量)。只需在nonlocal ctr函数顶部添加inner,问题就会消失:

def outer():
    ctr = 0

    def inner():
        nonlocal ctr
        ctr += 1

    inner()

解决方法(在python 2中)

由于nonlocal语句在python 2中不存在,因此我们必须谨慎。有两种简单的解决方法:

  • 删除所有对ctr的分配

    由于python仅将ctr视为局部变量,因为存在对该变量的赋值,因此如果我们删除所有名称为ctr的赋值,问题将消失。但是,如何在不赋值​​的情况下更改变量的值呢?简单:我们将变量包装在一个可变对象中,例如列表。然后,我们可以修改该列表,而无需为名称ctr分配值:

    def outer():
        ctr = [0]
    
        def inner():
            ctr[0] += 1
    
        inner()
    
  • ctr作为参数传递给inner

    def outer():
        ctr = 0
    
        def inner(ctr):
            ctr += 1
            return ctr
    
        ctr = inner(ctr)
    

答案 3 :(得分:-1)

如何在ctr之外(即在全局范围内)或任何其他类/函数声明outer?这将使变量可访问和写入。