什么是閉包?
簡(jiǎn)單說(shuō),閉包就是根據(jù)不同的配置信息得到不同的結(jié)果
再來(lái)看看專業(yè)的解釋:閉包(Closure)是詞法閉包(Lexical Closure)的簡(jiǎn)稱金矛,是引用了自由變量的函數(shù)。這個(gè)被引用的自由變量將和這個(gè)函數(shù)一同存在勺届,即使已經(jīng)離開(kāi)了創(chuàng)造它的環(huán)境也不例外驶俊。所以,有另一種說(shuō)法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體免姿。
python實(shí)例
例1
defmake_adder(addend):
defadder(augend):
returnaugend + addend
returnadder
p = make_adder(23)
q = make_adder(44)
printp(100)printq(100)
運(yùn)行結(jié)果:
123144
分析一下:
我們發(fā)現(xiàn),make_adder是一個(gè)函數(shù),包括一個(gè)參數(shù)addend,比較特殊的地方是這個(gè)函數(shù)里面又定義了一個(gè)新函數(shù),這個(gè)新函數(shù)里面的一個(gè)變量正好是外部make_adder的參數(shù).也就是說(shuō),外部傳遞過(guò)來(lái)的addend參數(shù)已經(jīng)和adder函數(shù)綁定到一起了,形成了一個(gè)新函數(shù),我們可以把a(bǔ)ddend看做新函數(shù)的一個(gè)配置信息,配置信息不同,函數(shù)的功能就不一樣了,也就是能得到定制之后的函數(shù).
再看看運(yùn)行結(jié)果,我們發(fā)現(xiàn),雖然p和q都是make_adder生成的,但是因?yàn)榕渲脜?shù)不同,后面再執(zhí)行相同參數(shù)的函數(shù)后得到了不同的結(jié)果.這就是閉包.
例2
defhellocounter(name):
count=[0]
defcounter():
count[0]+=1
print'Hello,',name,',',str(count[0])+' access!'
returncounter
hello = hellocounter('ma6174')
hello()
hello()
hello()
執(zhí)行結(jié)果
Hello, ysisl , 1 access!
Hello, ysisl , 2 access!
Hello, ysisl , 3 access!
分析一下
這個(gè)程序比較有趣,我們可以把這個(gè)程序看做統(tǒng)計(jì)一個(gè)函數(shù)調(diào)用次數(shù)的函數(shù).count[0]可以看做一個(gè)計(jì)數(shù)器,沒(méi)執(zhí)行一次hello函數(shù),count[0]的值就加1饼酿。也許你會(huì)有疑問(wèn):為什么不直接寫(xiě)count而用一個(gè)列表?這是python2的一個(gè)bug,如果不用列表的話,會(huì)報(bào)這樣一個(gè)錯(cuò)誤:
UnboundLocalError: local variable 'count' referenced before assignment.
什么意思?就是說(shuō)conut這個(gè)變量你沒(méi)有定義就直接引用了,我不知道這是個(gè)什么東西,程序就崩潰了.于是,再python3里面,引入了一個(gè)關(guān)鍵字:nonlocal,這個(gè)關(guān)鍵字是干什么的?就是告訴python程序,我的這個(gè)count變量是再外部定義的,你去外面找吧.然后python就去外層函數(shù)找,然后就找到了count=0這個(gè)定義和賦值,程序就能正常執(zhí)行了.
python3代碼
def?hello counter(name):
count=0
def?counter():
nonlocal?count
count+=1
print?'Hello,',name,',',str(count[0])+' access!'
return?counter
hello = hellocounter('ma6174')
hello()
hello()
hello()
例3
def?makebold(fn):
def?wrapped():
return""+ fn() +""
return?wrapped
def?makeitalic(fn):
def?wrapped():
return?""+ fn() +""
return?wrapped
@makebold@makeitalicdefhello():
return"hello world"
print?hello()
執(zhí)行結(jié)果
<b><i>hello worldi>b>
簡(jiǎn)單分析
怎么樣?這個(gè)程序熟悉嗎?這不是傳說(shuō)的的裝飾器嗎?對(duì),這就是裝飾器,其實(shí),裝飾器就是一種閉包,我們?cè)倩叵胍幌卵b飾器的概念:對(duì)函數(shù)(參數(shù),返回值等)進(jìn)行加工處理,生成一個(gè)功能增強(qiáng)版的一個(gè)函數(shù)。再看看閉包的概念,這個(gè)增強(qiáng)版的函數(shù)不就是我們配置之后的函數(shù)嗎?區(qū)別在于,裝飾器的參數(shù)是一個(gè)函數(shù)或類(lèi),專門(mén)對(duì)類(lèi)或函數(shù)進(jìn)行加工處理。
python里面的好多高級(jí)功能故俐,比如裝飾器想鹰,生成器,列表推到药版,閉包辑舷,匿名函數(shù)等,開(kāi)發(fā)中用一下槽片,可能會(huì)達(dá)到事半功倍的效果何缓!