[轉]Python閉包的改進 - 很好的分析,之前自己不懂.

Python也支持閉包,但在Python3.0以前,閉包不能訪問外部函數中的局部變量。Python3.0爲此引入了nonlocal關鍵字,從而完善了閉包訪問外部變量的機制。

在Python2.6中,如果像下面這樣定義函數:

1 >>> def outerFun():
2     outerVar = 0
3     def innerFun():
4         outerVar += 1
5     print outerVar
6     return innerFun

然後,調用outerFun返回的閉包,會導致錯誤:

1 >>> f = outerFun()
2 >>> f()
3  
4 Traceback (most recent call last):
5   File "<pyshell#15>", line 1in <module>
6     f()
7   File "<pyshell#12>", line 4in innerFun
8     outerVar += 1
9 UnboundLocalError: local variable 'outerVar' referenced before assignment

把錯誤消息“UnboundLocalError: local variable ‘outerVar’ referenced before assignment”翻譯成中文,就是“未綁定局部變量:引用局部變量’outerVar’之前沒有賦值”。啥意思呢?在內部函數innerFun中,outerVar被Python解釋器看成是內部函數innerFun中的局部變量,並不是我們認爲的外部(函數outerFun中的)變量。即在innerFun中,outerVar只是一個尚未賦值的變量——儘管與外部的outerVar同名,因此不能執行加法計算。Python3.0以前的版本提供了global關鍵字,通過這個關鍵字能夠在函數內部引用並重新綁定(修改)全局變量:

1 >>> x = 1
2 >>> def c():
3     global x
4     += 1
5     print x
6  
7 >>> c()
8 2


這裏通過global關鍵字在函數c的局部作用域中引用了全局變量x,因此就可以重新綁定(修改)全局變量了。雖然能訪問和修改全局變量,但還是不能解決閉包訪問外部函數變量的問題。爲此,Python3.0增加了一個新關鍵字——nonlocal,用於在嵌套函數中訪問外部變量:

01 >>> def outerFun():
02     outerVar = 0
03     def innerFun():
04         nonlocal outerVar   # 使用nonlocal引用外部函數變量
05         outerVar += 1
06         print(outerVar) # 注意,print在Python3.0中是函數,不是語句
07     return innerFun
08  
09 >>> f = outerFun()
10 >>> f()
11 1
12 >>> f()
13 2

而且,此時的外部變量對於內部的函數而言是共享的:

01 >>> def outerFun():
02     outerVar = 0
03     def innerFun():
04         nonlocal outerVar
05         outerVar += 1
06         print(outerVar)
07     def innerFun2():
08         nonlocal outerVar
09         outerVar *= 2
10         print(outerVar)
11     return [innerFun,innerFun2] # 通過列表返回兩個函數
12  
13 >>> ff = outerFun()
14 >>> ff[0]()
15 1
16 >>> ff[1]()
17 2
18 >>> ff[1]()    # 連續調用兩次innerFun2
19 4
20 >>> ff[0]()    # 結果表明,兩個閉包共享同一個變量
21 5

關於這一點改進的詳細內容,請參見PEP(Python Enhancement Proposals,Python改進建議)3104:Access to Names in Outer Scopes

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章