Python中的UnboundLocalError
我在这里做错了什么?
counter = 0 def increment(): counter += 1 increment()
上面的代码抛出一个UnboundLocalError
。
Python没有variables声明,所以它必须找出variables本身的范围 。 这是通过一个简单的规则来实现的:如果函数内部有一个variables赋值,该variables被认为是本地的。 [1]因此,线
counter += 1
隐式地使counter
本地increment()
。 尽pipe如此,尝试执行这一行将尝试在分配之前读取局部variablescounter
的值,导致UnboundLocalError
。 [2]
如果counter
是一个全局variables,那么global
关键字将会有所帮助。 如果increment()
是一个本地函数并counter
一个局部variables,那么可以在Python 3.x中使用nonlocal
。
您需要使用全局语句,以便您修改全局variables计数器,而不是本地variables:
counter = 0 def increment(): global counter counter += 1 increment()
如果counter
在其中定义的封闭范围不是全局范围,那么在Python 3.x上,可以使用非本地语句 。 在Python 2.x的相同情况下,您将无法重新分配非本地名称counter
,因此您需要使counter
变为可变并对其进行修改:
counter = [0] def increment(): counter[0] += 1 increment() print counter[0] # prints '1'
要回答你的主题中的问题,*是的,在Python中有闭包,除了它们只应用在函数内部,并且(在Python 2.x中)它们是只读的; 你不能将名字重新绑定到不同的对象(尽pipe如果对象是可变的,你可以修改它的内容)。 在Python 3.x中,可以使用nonlocal
关键字来修改一个闭包variables。
def incrementer(): counter = 0 def increment(): nonlocal counter counter += 1 return counter return increment increment = incrementer() increment() # 1 increment() # 2
*原始问题的标题问到关于Python中的闭包。
其他答案已经很好地解释了为什么你的代码抛出一个UnboundLocalError
的原因。
但在我看来,你正在尝试构build像itertools.count()
一样工作的东西。
那么你为什么不尝试一下,看看它是否适合你的情况:
>>> from itertools import count >>> counter = count(0) >>> counter count(0) >>> next(counter) 0 >>> counter count(1) >>> next(counter) 1 >>> counter count(2)
要修改函数内的全局variables,您必须使用全局关键字。
当你尝试这样做没有线
global counter
在增量定义的内部,创build了一个名为counter的局部variables,以防止整个程序可能依赖的计数器variables。
请注意,只有在修改variables时才需要使用全局variables; 你可以从增量内读取计数器,而不需要全局声明。
Python默认使用词法作用域,这意味着虽然封闭作用域可以访问其封闭作用域中的值,但不能修改它们(除非它们是用global
关键字声明为global
)。
闭包将封闭环境中的值绑定到本地环境中的名称。 然后本地环境可以使用绑定值,甚至可以将该名称重新分配给别的东西,但是它不能修改封闭环境中的绑定。
在你的情况下,你正试图把counter
作为局部variables而不是绑定值。 请注意,这个绑定在封闭环境中分配的x
值的代码工作正常:
>>> x = 1 >>> def f(): >>> return x >>> f() 1
尝试这个
counter = 0 def increment(): global counter counter += 1 increment()
Python不是纯粹的词汇范围。
看到这个: 在创build它们的函数中使用全局variables
和这个: http : //www.saltycrane.com/blog/2008/01/python-variable-scope-notes/