標籤:fun 使用 詞法 div 調用 class 定義 它的 body
一、函數作為傳回值
高階函數除了可以接受函數作為參數外,還可以把函數作為結果值返回。
1 >>> def lazy_sum(*args): 2 ... def sum(): 3 ... ax = 0 4 ... for n in args: 5 ... ax = ax + n 6 ... return ax 7 ... return sum 8 ... 9 >>> f = lazy_sum(1, 3, 5, 7, 9)10 >>> f11 <function lazy_sum.<locals>.sum at 0x1014ae730>12 >>> f()13 25
當我們調用lazy_sum()時,每次調用都會返回一個新的函數,即使傳入相同的參數:
1 >>> f1 = lazy_sum(1, 3, 5, 7)2 >>> f2 = lazy_sum(1, 3, 5, 7)3 >>> f14 <function lazy_sum.<locals>.sum at 0x1014ae8c8>5 >>> f26 <function lazy_sum.<locals>.sum at 0x1014ae7b8>7 >>> f1 == f28 False
二、閉包
在電腦科學中,閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,是引用了自由變數的函數。這個被引用的自由變數將和這個函數一同存在,即使已經離開了創造它的環境也不例外。所以,有另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。閉包在運行時可以有多個執行個體,不同的引用環境和相同的函數組合可以產生不同的執行個體。
簡單的說,這種內建函式可以使用外部函數變數的行為,就叫閉包。
在這個例子中,我們在函數lazy_sum中又定義了函數sum,並且,內建函式sum可以引用外部函數lazy_sum的參數和局部變數,當lazy_sum返回函數sum時,相關參數和變數都儲存在返回的函數中,這種稱為“閉包(Closure)”的程式結構擁有極大的威力。
注意到返回的函數在其定義內部引用了局部變數args,所以,當一個函數返回了一個函數後,其內部的局部變數還被新函數引用,所以,閉包用起來簡單,實現起來可不容易。
返回閉包時牢記一點:返回函數不要引用任何迴圈變數,或者後續會發生變化的變數。
1 >>> def count(): 2 ... fs = [] 3 ... for i in range(1, 4): 4 ... def f(): 5 ... return i * i 6 ... fs.append(f) 7 ... return fs 8 ... 9 >>> f1, f2, f3 = count()10 >>> f1()11 912 >>> f2()13 914 >>> f3()15 9
全部都是9!原因就在於返回的函數引用了迴圈變數i,但它並非立刻執行。等到3個函數都返回時,它們所引用的變數i已經變成了3,因此最終結果為9。
如果一定要引用迴圈變數怎麼辦?方法是再建立一個函數,用該函數的參數綁定迴圈變數當前的值,無論該迴圈變數後續如何更改,已綁定到函數參數的值不變:
1 >>> def count(): 2 ... def f(j): 3 ... def g(): 4 ... return j * j 5 ... return g 6 ... fs = [] 7 ... for i in range(1, 4): 8 ... fs.append(f(i)) 9 ... return fs10 ... 11 >>> f1, f2, f3 = count()12 >>> f1()13 114 >>> f2()15 416 >>> f3()17 9
python 閉包 Closure 函數作為傳回值