前言
首先看看閉包的概念:閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,即使已經離開了創造它的環境也不例外。所以,閉包是由函數和與其相關的引用環境組合而成的實體。
一、函數作為返回值
高階函數除了可以接受函數作為參數外,還可以把函數作為結果值返回。
>>> def lazy_sum(*args):... def sum():... ax = 0... for n in args:... ax = ax + n... return ax... return sum... >>> f = lazy_sum(1, 3, 5, 7, 9)>>> f<function lazy_sum.<locals>.sum at 0x1014ae730>>>> f()25
當我們調用lazy_sum()時,每次調用都會返回一個新的函數,即使傳入相同的參數:
>>> f1 = lazy_sum(1, 3, 5, 7)>>> f2 = lazy_sum(1, 3, 5, 7)>>> f1<function lazy_sum.<locals>.sum at 0x1014ae8c8>>>> f2<function lazy_sum.<locals>.sum at 0x1014ae7b8>>>> f1 == f2False
二、閉包
在計算機科學中,閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,即使已經離開了創造它的環境也不例外。所以,有另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。閉包在運行時可以有多個實例,不同的引用環境和相同的函數組合可以產生不同的實例。
簡單的說,這種內部函數可以使用外部函數變量的行為,就叫閉包。
在這個例子中,我們在函數lazy_sum中又定義了函數sum,并且,內部函數sum可以引用外部函數lazy_sum的參數和局部變量,當lazy_sum返回函數sum時,相關參數和變量都保存在返回的函數中,這種稱為“閉包(Closure)”的程序結構擁有極大的威力。
注意到返回的函數在其定義內部引用了局部變量args,所以,當一個函數返回了一個函數后,其內部的局部變量還被新函數引用,所以,閉包用起來簡單,實現起來可不容易。
返回閉包時牢記一點:返回函數不要引用任何循環變量,或者后續會發生變化的變量。
>>> def count():... fs = []... for i in range(1, 4):... def f():... return i * i... fs.append(f)... return fs... >>> f1, f2, f3 = count()>>> f1()9>>> f2()9>>> f3()9
全部都是9!原因就在于返回的函數引用了循環變量i,但它并非立刻執行。等到3個函數都返回時,它們所引用的變量i已經變成了3,因此最終結果為9。
如果一定要引用循環變量怎么辦?方法是再創建一個函數,用該函數的參數綁定循環變量當前的值,無論該循環變量后續如何更改,已綁定到函數參數的值不變:
新聞熱點
疑難解答