2012-02-13 36 views
93

我在这里做错了什么?Python中的UnboundLocalError

counter = 0 

def increment(): 
    counter += 1 

increment() 

上面的代码会抛出一个UnboundLocalError

+11

@ZeroPiraeus:你为什么锤问题与40K +的看法,这是“UnboundLocalError”的第一个结果在谷歌,作为一个几乎相同的新问题,你回答的副本,而不是简单地发布你的答案*在这里*? – vaultah 2017-01-03 00:26:05

+1

这个问题和它目前标记为重复的问题正在[Python聊天室](http://chat.stackoverflow.com/transcript/message/34899645#34899645)中讨论。 – 2017-01-03 01:30:44

+3

这里的许多答案都表示使用'global',尽管有效,但在其他选项存在的情况下,通常不推荐使用可修改的全局变量。 – 2017-01-03 01:34:48

回答

97

Python没有变量声明,所以它必须弄清楚的变量本身scope。它是通过一个简单的规则来实现的:如果函数内部有一个变量赋值,该变量被认为是本地的。 [1]因此,线

counter += 1 

隐含使得counter本地increment()。尽管如此,尝试执行此行将在分配之前尝试读取本地变量counter的值,从而产生UnboundLocalError[2]

如果counter是一个全局变量,该global关键字会有所帮助。如果increment()是本地函数,并且counter是本地变量,则可以在Python 3.x中使用nonlocal

+2

python 3 docs has a [faq page on why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value](https://docs.python.org/3/faq/programming .html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value)通过[unboundlocalerror-local-variable-l-referenced-before-assignment-python](http:// stackoverflow.com/questions/21456739/unboundlocalerror-local-variable-l-referenced-before-assignment-python) – here 2014-05-04 07:19:41

+0

一个注意到了我,我有一个变量声明在文件的顶部,我可以读取一个函数没有问题,但是要写入我已经在文件顶部声明的变量,我必须使用全局变量。 – mouckatron 2018-02-06 14:35:46

3

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

当您尝试这样做没有行

global counter 

增量的定义内,局部变量命名的计数器产生,从而让你从打乱计数器变量,整个程序可能取决于。

请注意,您只需要在修改变量时使用全局;你可以在增量内读取计数器而不需要全局声明。

51

您需要使用global statement让你修改的全局变量计数器,而不是一个局部变量:

counter = 0 

def increment(): 
    global counter 
    counter += 1 

increment() 

如果counter在规定的封闭范围是不是全球范围内,关于Python 3.x你可以使用nonlocal statement。在关于Python 2.x中相同的情况下,你就没有办法重新分配到外地名counter,所以你需要做counter可变和修改:

counter = [0] 

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

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

酷..它工作+1 – 2016-10-06 06:26:52

+0

它的工作表示感谢。 – 2016-11-22 09:05:15

2

试试这个

counter = 0 

def increment(): 
    global counter 
    counter += 1 

increment() 
0
+0

尽管这个链接可能回答这个问题,但最好在这里包含答案的重要部分,并提供供参考的链接。如果链接页面更改,则仅链接答案可能会失效。 - [来自评论](/ review/low-quality-posts/19036082) – munk 2018-03-07 19:05:19

+0

@munk酷,你意识到这是一个链接到另一个答案呢? – Marcin 2018-03-07 20:33:30

3

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

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

在你的情况下,你试图把counter当作局部变量而不是绑定值。请注意,此代码,结合在封闭的环境中分配的x值,正常工作:

>>> x = 1 

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

>>> f() 
1 
11

要回答这个问题在你的主题行,*是的,有在Python关闭,除非他们只是内部应用一个函数,还有(在Python 2.x中)它们是只读的;您不能将该名称重新绑定到不同的对象(但如果该对象是可变的,则可以修改其内容)。在Python 3.x中,可以使用nonlocal关键字来修改闭包变量。

def incrementer(): 
    counter = 0 
    def increment(): 
     nonlocal counter 
     counter += 1 
     return counter 
    return increment 

increment = incrementer() 

increment() # 1 
increment() # 2 

*原始问题的标题问到Python中的闭包。

6

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

但在我看来,你正在试图建立一个像itertools.count()一样工作的东西。

那么你为什么不尝试一下,看看它是否适合你的情况:

>>> from itertools import count 
>>> counter = count(0) 
>>> counter 
count(0) 
>>> next(counter) 
0 
>>> counter 
count(1) 
>>> next(counter) 
1 
>>> counter 
count(2)