閉包并不是什么新奇的概念,它早在高級語言開始發(fā)展的年代就產(chǎn)生了。閉包(Closure)是詞法閉包(Lexical Closure)的簡稱。對閉包的具體定義有很多種說法,這些說法大體可以分為兩類:
一種說法認(rèn)為閉包是符合一定條件的函數(shù),比如參考資源中這樣定義閉包:閉包是在其詞法上下文中引用了自由變量的函數(shù)。
另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實體。比如參考資源中就有這樣的的定義:在實現(xiàn)深約束時,需要創(chuàng)建一個能顯式表示引用環(huán)境的東西,并將它與相關(guān)的子程序捆綁在一起,這樣捆綁起來的整體被稱為閉包。
就像這樣:
#python 中的閉包 ... def func(data): ... count = [data] ... def wrap(): ... count[0] += 1 ... return count[0] ... return wrap ... ... a = func(1) >>> a() 5: 2 >>> a() 6: 3 def func(x): ... return lambda y :y+x >>> b = func(1) >>> b(1) 7: 2 >>> b(2) 8: 3 >>> print b #這里b是個function 在ruby中是procat 0x01AC68F0> def addx(x): ... def adder (y): return x + y ... return adder >>> add8 = addx(8) >>> add8(8) 9: 16
簡單說,閉包就是根據(jù)不同的配置信息得到不同的結(jié)果
python實例
看概念總是讓人摸不著頭腦,看幾個python小例子就會了
例1
def make_adder(addend): def adder(augend): return augend + addend return adder p = make_adder(23) q = make_adder(44) print p(100) print q(100)
運行結(jié)果:
123 144
分析一下:
我們發(fā)現(xiàn),make_adder是一個函數(shù),包括一個參數(shù)addend,比較特殊的地方是這個函數(shù)里面又定義了一個新函數(shù),這個新函數(shù)里面的一個變量正好是外部make_adder的參數(shù).也就是說,外部傳遞過來的addend參數(shù)已經(jīng)和adder函數(shù)綁定到一起了,形成了一個新函數(shù),我們可以把addend看做新函數(shù)的一個配置信息,配置信息不同,函數(shù)的功能就不一樣了,也就是能得到定制之后的函數(shù).
再看看運行結(jié)果,我們發(fā)現(xiàn),雖然p和q都是make_adder生成的,但是因為配置參數(shù)不同,后面再執(zhí)行相同參數(shù)的函數(shù)后得到了不同的結(jié)果.這就是閉包.
例2
def hellocounter (name): count=[0] def counter(): count[0]+=1 print 'Hello,',name,',',str(count[0])+' access!' return counter hello = hellocounter('ma6174') hello() hello() hello()
執(zhí)行結(jié)果
Hello, ysisl , 1 access! Hello, ysisl , 2 access! Hello, ysisl , 3 access!
分析一下
這個程序比較有趣,我們可以把這個程序看做統(tǒng)計一個函數(shù)調(diào)用次數(shù)的函數(shù).count[0]可以看做一個計數(shù)器,沒執(zhí)行一次hello函數(shù),count[0]的值就加1。也許你會有疑問:為什么不直接寫count而用一個列表?這是python2的一個bug,如果不用列表的話,會報這樣一個錯誤:
UnboundLocalError: local variable 'count' referenced before assignment.
什么意思?就是說conut這個變量你沒有定義就直接引用了,我不知道這是個什么東西,程序就崩潰了.于是,再python3里面,引入了一個關(guān)鍵字:nonlocal,這個關(guān)鍵字是干什么的?就是告訴python程序,我的這個count變量是再外部定義的,你去外面找吧.然后python就去外層函數(shù)找,然后就找到了count=0這個定義和賦值,程序就能正常執(zhí)行了.
python3 代碼
def hellocounter (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 @makeitalic def hello(): return "hello world" print hello()
執(zhí)行結(jié)果
hello world
簡單分析
怎么樣?這個程序熟悉嗎?這不是傳說的的裝飾器嗎?對,這就是裝飾器,其實,裝飾器就是一種閉包,我們再回想一下裝飾器的概念:對函數(shù)(參數(shù),返回值等)進(jìn)行加工處理,生成一個功能增強(qiáng)版的一個函數(shù)。再看看閉包的概念,這個增強(qiáng)版的函數(shù)不就是我們配置之后的函數(shù)嗎?區(qū)別在于,裝飾器的參數(shù)是一個函數(shù)或類,專門對類或函數(shù)進(jìn)行加工處理。
python里面的好多高級功能,比如裝飾器,生成器,列表推到,閉包,匿名函數(shù)等,開發(fā)中用一下,可能會達(dá)到事半功倍的效果!
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
