关于python:不理解UnboundLocalError发生的原因

Don't understand why UnboundLocalError occurs

本问题已经有最佳答案,请猛点这里访问。

我在这里做错什么了?

1
2
3
4
5
6
counter = 0

def increment():
  counter += 1

increment()

上面的代码抛出了一个UnboundLocalError


python没有变量声明,因此必须确定变量本身的范围。它是通过一个简单的规则来实现的:如果在一个函数中有一个变量的赋值,那么这个变量就被认为是局部变量。

1
counter += 1

隐含地使counter成为increment()的局部。但是,尝试执行此行会在赋值之前尝试读取局部变量counter的值,从而产生UnboundLocalError。[2]

如果counter是一个全局变量,那么global关键字将有所帮助。如果increment()是局部函数,而counter是局部变量,则可以在python 3.x中使用nonlocal


您需要使用global语句来修改全局变量计数器,而不是局部变量:

1
2
3
4
5
6
7
counter = 0

def increment():
  global counter
  counter += 1

increment()

如果counter中定义的封闭范围不是全局范围,那么在python 3.x上可以使用非本地语句。在python 2.x上的相同情况下,您将无法重新分配到非本地名称counter,因此需要使counter可变并修改它:

1
2
3
4
5
6
7
counter = [0]

def increment():
  counter[0] += 1

increment()
print counter[0]  # prints '1'


要回答主题行中的问题,*是的,python中有闭包,但它们只应用于函数内部,而且(在python 2.x中)它们是只读的;不能将名称重新绑定到其他对象(尽管如果对象是可变的,则可以修改其内容)。在python 3.x中,可以使用nonlocal关键字修改闭包变量。

1
2
3
4
5
6
7
8
9
10
11
12
def incrementer():
    counter = 0
    def increment():
        nonlocal counter
        counter += 1
        return counter
    return increment

increment = incrementer()

increment()   # 1
increment()   # 2

*最初问题的标题是关于Python中的闭包。


您的代码为什么抛出一个UnboundLocalError的原因已经在其他答案中得到了很好的解释。

但在我看来,你是在试图建立一个类似于itertools.count()的东西。

所以你为什么不试试看它是否适合你的情况:

1
2
3
4
5
6
7
8
9
10
11
12
>>> from itertools import count
>>> counter = count(0)
>>> counter
count(0)
>>> next(counter)
0
>>> counter
count(1)
>>> next(counter)
1
>>> counter
count(2)

默认情况下,python具有词法作用域,这意味着尽管封闭作用域可以访问其封闭作用域中的值,但它不能修改这些值(除非使用global关键字将它们声明为全局值)。

闭包将封闭环境中的值绑定到本地环境中的名称。然后,本地环境可以使用绑定值,甚至可以将该名称重新分配给其他名称,但它不能修改封闭环境中的绑定。

在您的案例中,您试图将counter视为局部变量,而不是绑定值。请注意,此代码绑定在封闭环境中分配的x的值,可以正常工作:

1
2
3
4
5
6
7
>>> x = 1

>>> def f():
>>>  return x

>>> f()
1

要修改函数内的全局变量,必须使用global关键字。

当你试着不打电话的时候

1
global counter

在增量定义的内部,会创建一个名为counter的局部变量,以防止您弄乱整个程序可能依赖的计数器变量。

注意,只有在修改变量时才需要使用global;您可以从increment中读取counter,而不需要使用global语句。


试试这个

1
2
3
4
5
6
7
counter = 0

def increment():
  global counter
  counter += 1

increment()

python不是纯词汇范围的。

请参见:在创建全局变量的函数之外的函数中使用全局变量

以下是:http://www.saltycrane.com/blog/2008/01/python-variable-scope-notes/