首先, 說說python裡面的閉包吧:
1. 需要函數嵌套, 就是一個函數裡面再寫一個函數.
2. 外部函數需要返回一個內建函式的引用
3. 外部函數中有一些局部變數, 並且, 這些局部變數在內建函式中有使用
概念:
1. 自由變數: 外部函數中定義的局部變數, 並且在內建函式中被使用.
2. 閉包: 那個使用了自由變數並被返回的內建函式就稱為閉包.
一個例子:(來自<python核心編程>)
def counter(start_at=0):<br /> count = [start_at]<br /> def incr():<br /> count[0] += 1<br /> return count[0]<br /> return incr
問題的提出: 關於python閉包的一個問題 , 呵呵, 論壇一位網友提出的問題: 自由變數只能是list嗎?
def f():<br /> a = [1, 2]<br /> b = 1<br /> c = 'hello'<br /> d = (1, )<br /> e = True<br /> f = {1: 2}</p><p> def inf():<br /> print locals()<br /> a[0] += 1<br /> b = 2<br /> c = 3<br /> d = (2, )<br /> e = False<br /> f[1] = 3<br /> return a[0]<br /> return inf</p><p>a = f()<br />t = a()<br />print t
上面這一段代碼中, 內建函式inf第一句列印了locals(), 最終列印的結果只有a和f, 這段代碼我的測試環境是python2.5, windows平台...對於這段, 我總結:
1. 內建函式中, 遇到一個變數, 如果是試圖改變它的子項目(集合類型)或自己名稱空間(比如函數作為變數或對象作為變數時, 自己同時是名稱空間)內部其他名稱的引用時, 將會合法的引用到外部變數.
2. 內建函式中, 遇到一個變數, 如果試圖直接改變其自身, 多數情況都會得到"使用前未指定"的錯誤, 請看原因:
def f():<br /> a = 1<br /> def inf():<br /> a += 1<br /> return a<br /> return inf
最重要的就在a+=1這一句, 這裡, python實際上會認為你是在建立一個新的本地變數並為他賦值, 也就是說, python的解譯器認為a+=1是a = a + 1, 而此時就很明顯了, 本地變數中目前沒有a, 所以, 就得到了我們上面說的那個錯誤...
3. 通常需要在閉包內部去修改外部函數變數的時候, 我們需要藉助一些集合類型或有名稱空間的對象進行操作.
以上這部分都是python3.0之前的情況, 在3.0之後, 加入了一個新的關鍵字nonlocal, 就像當初的global關鍵字解決函數內修改全域變數的問題一樣漂亮, nonlocal將閉包內修改外部變數的問題也很優美的搞定了.
def f():<br /> a1 = 'hello'<br /> a2 = 1<br /> a3 = o()<br /> a3.x = 1<br /> def inf():<br /> print(locals())<br /> nonlocal a2, a1<br /> a1 += ' world'<br /> a2 += 2<br /> a3.x += 1<br /> return a1, a2, a3<br /> return inf
上面的代碼中, 通過在閉包內, 使用外部變數之前, 用nonlocal去聲明一下要在閉包中進行修改的那兩個變數不是本地變數, 就OK了, 和global的用法完全一致, 這樣, 我們就可以在其後的程式碼片段中, 修改普通的外部變數了.....