注意到返回的函數(shù)在其定義內(nèi)部引用了局部變量args
,所以,當(dāng)一個(gè)函數(shù)返回了一個(gè)函數(shù)后,其內(nèi)部的局部變量還被新函數(shù)引用,所以,閉包用起來簡單,實(shí)現(xiàn)起來可不容易。
另一個(gè)需要注意的問題是,返回的函數(shù)并沒有立刻執(zhí)行,而是直到調(diào)用了f()
才執(zhí)行。我們來看一個(gè)例子:
def count(): fs = [] for i in range(1, 4): def f(): return i*i fs.append(f) return fsf1, f2, f3 = count()在上面的例子中,每次循環(huán),都創(chuàng)建了一個(gè)新的函數(shù),然后,把創(chuàng)建的3個(gè)函數(shù)都返回了。
你可能認(rèn)為調(diào)用f1()
,f2()
和f3()
結(jié)果應(yīng)該是1
,4
,9
,但實(shí)際結(jié)果是:
>>> f1()9>>> f2()9>>> f3()9全部都是9
!原因就在于返回的函數(shù)引用了變量i
,但它并非立刻執(zhí)行。等到3個(gè)函數(shù)都返回時(shí),它們所引用的變量i
已經(jīng)變成了3
,因此最終結(jié)果為9
。
返回閉包時(shí)牢記的一點(diǎn)就是:返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會發(fā)生變化的變量。
如果一定要引用循環(huán)變量怎么辦?方法是再創(chuàng)建一個(gè)函數(shù),用該函數(shù)的參數(shù)綁定循環(huán)變量當(dāng)前的值,無論該循環(huán)變量后續(xù)如何更改,已綁定到函數(shù)參數(shù)的值不變:
def count(): def f(j): def g(): return j*j return g fs = [] for i in range(1, 4): fs.append(f(i)) # f(i)立刻被執(zhí)行,因此i的當(dāng)前值被傳入f() return fs再看看結(jié)果:
>>> f1, f2, f3 = count()>>> f1()1>>> f2()4>>> f3()9缺點(diǎn)是代碼較長,可利用lambda函數(shù)縮短代碼。
小結(jié)
一個(gè)函數(shù)可以返回一個(gè)計(jì)算結(jié)果,也可以返回一個(gè)函數(shù)。
返回一個(gè)函數(shù)時(shí),牢記該函數(shù)并未執(zhí)行,返回函數(shù)中不要引用任何可能會變化的變量。
參考源碼
return_func.py
新聞熱點(diǎn)
疑難解答
圖片精選