閉包是編程語言通用的一種編程范式,且是面試中必問的問題之一。初學者可能在閉包中糾結好一陣子,當時學習JavaScript時我也在這里踩了不少坑,以Python的閉包為例寫點注意事項就當是學習的一點總結吧。
高階函數除了可以將函數作為參數之外,還可以將函數作為結果值返回,閉包的具體定義可以谷歌一下,通俗點來講,閉包就是返回函數以及函數的自我調用,我是這么理解的。以如下最精簡的函數為例解釋閉包:
當我們調用函數f時,返回的并不是階乘結果,而是返回的g函數體
調用返回結果才會返回階乘結果
注:不可直接調用函數內部的函數,即g()
我們在函數f內部定義了函數g,內部函數可以引用外部函數f的參數和局部變量,當函數f返回函數g時,相關的參數和局部變量都保存在返回的函數g中,這種就成為閉包。
需要注意的問題是,返回的函數并沒有立刻執行,而是直到調用了f()才執行。我們來看一個例子:
可能有人會猜想結果為1,4,9,實際執行打印出來的結果如下
原因就在于返回的函數引用了變量i,但它并非立刻執行。等到3個函數都返回時,它們所引用的變量i已經變成了3,因此最終結果為9。
返回閉包時牢記的一點就是:返回函數不要引用任何循環變量,或者后續會發生變化的變量。
如果一定要引用循環變量怎么辦?方法是再創建一個函數,用該函數的參數綁定循環變量當前的值,無論該循環變量后續如何更改,已綁定到函數參數的值不變:
這回執行結果符合預期了: