起因于慕課上的一段代碼:
# 希望一次返回3個(gè)函數(shù)碴里,分別計(jì)算1x1,2x2,3x3:
def count():
? ? fs = []
? ? for i in range(1, 4):
? ? ? ? def f():
? ? ? ? ? ? return i*i
? ? ? ? fs.append(f)
? ? return fs
f1, f2, f3 = count()
print f1,f2,f3 >>> 9, 9, 9
要求正常實(shí)現(xiàn)功能捉蚤,看不明白……在評論區(qū)抄了一段:
def count():
? ? fs = []
? ? for i in range(1, 4):
? ? ? ? def f(m = i):
? ? ? ? ? ? return m * m
? ? ? ? fs.append(f)
? ? return fs
f1, f2, f3 = count()
print f1(), f2(), f3() >>> 1, 4, 9
媳危?烦周?帚稠?
繼續(xù)看評論:
問題的產(chǎn)生是因?yàn)楹瘮?shù)只在執(zhí)行時(shí)才去獲取外層參數(shù)i孵运,若函數(shù)定義時(shí)可以獲取到i穆律,問題便可解決惠呼。而默認(rèn)參數(shù)正好可以完成定義時(shí)獲取i值且運(yùn)行函數(shù)時(shí)無需參數(shù)輸入的功能,所以在函數(shù)f()定義中改為f(m = i),函數(shù)f返回值改為m*m即可.
好像懂了又好像沒懂峦耘。
大概就是count()返回了fs剔蹋,其中保存了3個(gè)沒有執(zhí)行過的f,分別賦予變量f1,f2,f3
在開始的那段代碼中辅髓,返回3個(gè)f時(shí)i已經(jīng)變成3泣崩,這時(shí)再調(diào)用就會出現(xiàn)f(3),f(3)洛口,f(3) = 9矫付,9,9
而第二段代碼中第焰,每次返回f時(shí)當(dāng)前的i被固定在了變量m中买优,因此調(diào)用時(shí)為f(1),f(2),f(3) = 1杀赢,4烘跺,9
換言之,讓fs中直接保存每次循環(huán)中執(zhí)行的結(jié)果也可以達(dá)到目的:
def count3():
? ? fs = []
? ? for i in range(1,4):
? ? ? ? fs.append(i*i)
? ? return fs
f1, f2, f3 = count3()
print f1, f2, f3 >>> 1, 4, 9
最后看看課程中對此的結(jié)論:
像這種內(nèi)層函數(shù)引用了外層函數(shù)的變量(參數(shù)也算變量)脂崔,然后返回內(nèi)層函數(shù)的情況滤淳,稱為閉包(Closure)。
閉包的特點(diǎn)是返回的函數(shù)還引用了外層函數(shù)的局部變量砌左,所以娇钱,要正確使用閉包,就要確保引用的局部變量在函數(shù)返回后不能變绊困。
因此文搂,返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會發(fā)生變化的變量秤朗。