Python的範圍規則101:
在函數體結合的名稱被認爲local
除非顯式地聲明global
(Python的2.x和3.x)或nonlocal
(Python的3.x的只)。無論分配發生在函數的正文中,這都是真實的。試圖在綁定之前讀取局部變量當然是一個錯誤。
如果一個名字被讀取但沒有被綁定到一個函數的主體中,它會在封閉的作用域(外部函數(如果有的話)是全局作用域)中被查找。 NB:函數參數是事實上的本地名稱,所以它們永遠不會在封閉範圍內查找。
注意a += 1
主要是針對a = a + 1
的快捷方式,所以在你的例子a
是本地(綁定在函數體,而不是明確地聲明的全局或外地),但你嘗試讀它(的a = a+1
的RHS )在它被綁定之前。
在Python 3,你可以用nonlocal
語句解決這個問題:
>>> def outer(a):
... def change():
... nonlocal a
... a += 1
... print("before : {}".format(a))
... change()
... print ("after : {}".format(a))
...
>>> outer(42)
before : 42
after : 43
Python 2裏沒有nonlocal
所以官方hack是住變量在一個可變的容器(通常爲list
,但任何可變對象會做):
>>> def outer(a):
... _a = [a]
... def change():
... _a[0] += 1
... print("before : {}".format(_a[0]))
... change()
... print ("after : {}".format(_a[0]))
...
>>> outer(42)
before : 42
after : 43
這是相當難看,至少可以說。
現在雖然閉包是很方便,他們大多是對象的功能對應:一組功能之間共享狀態,同時保持這種狀態的封裝方式,所以如果你發現你需要一個nonlocal
變量也許一個適當的類可能是一個更乾淨的解決方案(儘管可能不適用於您的示例,它不會返回內部函數,但僅在內部使用它)。
您是否嘗試過在功能'全球了'? – Fomalhaut
這是同樣的事情,用'global':您可以訪問一個全局變量,而是試圖修改,而不會'全球var'將失敗。 – ForceBru
無論採用何種方法來解決這個問題,像這樣伸出援手並導致任意的副作用都不是很好的編程練習。 – mVChr