2012-02-13 33 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)