摘要:所以,有另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。
對(duì)于已經(jīng)對(duì) 閉包 或者 裝飾器有一定概念的,可以直接通過右側(cè)標(biāo)題目錄直接定位到相應(yīng)段落查看所需的內(nèi)容。
什么是裝飾器?裝飾器(Decorator)相對(duì)簡單,咱們先介紹它:“裝飾器的功能是將被裝飾的函數(shù)當(dāng)作參數(shù)傳遞給與裝飾器對(duì)應(yīng)的函數(shù)(名稱相同的函數(shù)),并返回包裝后的被裝飾的函數(shù)”,聽起來有點(diǎn)繞,沒關(guān)系,直接看示意圖,其中 a 為與裝飾器 @a 對(duì)應(yīng)的函數(shù), b 為裝飾器修飾的函數(shù),裝飾器@a的作用是:
簡而言之:@a 就是將 b 傳遞給 a(),并返回新的 b = a(b)
栗子:
上面使用@dobi來表示裝飾器,其等同于:qinfeng = dobi(qinfeng)
因此裝飾器本質(zhì)上就是個(gè)語法糖,其作用為簡化代碼,以提高代碼可讀性,運(yùn)行上段代碼的結(jié)果為:
解析過程是這樣子的:
1.python 解釋器發(fā)現(xiàn)@dobi,就去調(diào)用與其對(duì)應(yīng)的函數(shù)( dobi 函數(shù))
2.dobi 函數(shù)調(diào)用前要指定一個(gè)參數(shù),傳入的就是@dobi下面修飾的函數(shù),也就是 qinfeng()
3.dobi() 函數(shù)執(zhí)行,調(diào)用 qinfeng(),qinfeng() 打印“dobi”
首先還得從基本概念說起,什么是閉包呢?來看下維基上的解釋:
在計(jì)算機(jī)科學(xué)中,閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,是引用了自由變量的函數(shù)。這個(gè)被引用的自由變量將和這個(gè)函數(shù)一同存在,即使已經(jīng)離開了創(chuàng)造它的環(huán)境也不例外。所以,有另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。閉包在運(yùn)行時(shí)可以有多個(gè)實(shí)例,不同的引用環(huán)境和相同的函數(shù)組合可以產(chǎn)生不同的實(shí)例。
....
上面提到了兩個(gè)關(guān)鍵的地方: 自由變量 和 函數(shù), 這兩個(gè)關(guān)鍵稍后再說。還是得在贅述下“閉包”的意思,望文知意,可以形象的把它理解為一個(gè)封閉的包裹,這個(gè)包裹就是一個(gè)函數(shù),當(dāng)然還有函數(shù)內(nèi)部對(duì)應(yīng)的邏輯,包裹里面的東西就是自由變量,自由變量可以在隨著包裹到處游蕩。當(dāng)然還得有個(gè)前提,這個(gè)包裹是被創(chuàng)建出來的。
在通過Python的語言介紹一下,一個(gè)閉包就是你調(diào)用了一個(gè)函數(shù)A,這個(gè)函數(shù)A返回了一個(gè)函數(shù)B給你。這個(gè)返回的函數(shù)B就叫做閉包。你在調(diào)用函數(shù)A的時(shí)候傳遞的參數(shù)就是自由變量。
舉個(gè)栗子:
def func(name): def inner_func(age): print "name:", name, "age:", age return inner_func bb = func("the5fire") bb(26) # >>> name: the5fire age: 26
這里面調(diào)用func的時(shí)候就產(chǎn)生了一個(gè)閉包——inner_func,并且該閉包持有自由變量——name,因此這也意味著,當(dāng)函數(shù)func的生命周期結(jié)束之后,name這個(gè)變量依然存在,因?yàn)樗婚]包引用了,所以不會(huì)被回收。
另外再說一點(diǎn),閉包并不是Python中特有的概念,所有把函數(shù)做為一等公民的語言均有閉包的概念。不過像Java這樣以class為一等公民的語言中也可以使用閉包,只是它得用類或接口來實(shí)現(xiàn)。
nonlocal 語句在 python 的函數(shù)內(nèi),可以直接引用外部變量,但不能改寫外部變量,因此如果在閉包中直接改寫父函數(shù)的變量,就會(huì)發(fā)生錯(cuò)誤:
在 python 2 中可以在函數(shù)內(nèi)使用 global 語句,但全局變量在任何語言中都不被提倡,因?yàn)樗茈y控制,python 3 中引入了 nonlocal 語句解決了這個(gè)問題:
Nonlocal 與 global 的區(qū)別在于 nonlocal 語句會(huì)去搜尋本地變量與全局變量之間的變量,其會(huì)優(yōu)先尋找層級(jí)關(guān)系與閉包作用域最近的外部變量。
閉包與裝飾器上面已經(jīng)簡單演示了裝飾器的功能,事實(shí)上,裝飾器就是一種的閉包的應(yīng)用,只不過其傳遞的是函數(shù):
@makeitalic 裝飾器將函數(shù) hello 傳遞給函數(shù) makeitalic,函數(shù) makeitalic 執(zhí)行完畢后返回被包裝后的 hello 函數(shù),而這個(gè)過程其實(shí)就是通過閉包實(shí)現(xiàn)的。@makebold 也是如此,只不過其傳遞的是 @makeitalic 裝飾過的 hello 函數(shù),因此最后的執(zhí)行結(jié)果 在 外層,這個(gè)功能如果不用裝飾器,其實(shí)就是顯式的使用閉包:
閉包的作用閉包的最大特點(diǎn)是可以將父函數(shù)的變量與內(nèi)部函數(shù)綁定,并返回綁定變量后的函數(shù)(也即閉包),此時(shí)即便生成閉包的環(huán)境(父函數(shù))已經(jīng)釋放,閉包仍然存在,這個(gè)過程很像類(父函數(shù))生成實(shí)例(閉包),不同的是父函數(shù)只在調(diào)用時(shí)執(zhí)行,執(zhí)行完畢后其環(huán)境就會(huì)釋放,而類則在文件執(zhí)行時(shí)創(chuàng)建,一般程序執(zhí)行完畢后作用域才釋放,因此對(duì)一些需要重用的功能且不足以定義為類的行為,使用閉包會(huì)比使用類占用更少的資源,且更輕巧靈活,現(xiàn)舉一例:假設(shè)我們僅僅想打印出各類動(dòng)物的叫聲,分別以類和閉包來實(shí)現(xiàn):
可以看到輸出結(jié)果是完全一樣的,但顯然類的實(shí)現(xiàn)相對(duì)繁瑣,且這里只是想輸出一下動(dòng)物的叫聲,定義一個(gè) Animal 類未免小題大做,而且 voice 函數(shù)在執(zhí)行完畢后,其作用域就已經(jīng)釋放,但 Animal 類及其實(shí)例 dog 的相應(yīng)屬性卻一直貯存在內(nèi)存中:
而這種占用對(duì)于實(shí)現(xiàn)該功能后,則是沒有必要的。
除此之外,閉包還有很多其他功能,比如用于封裝等,另外,閉包有效的減少了函數(shù)參數(shù)的數(shù)目,這對(duì)并行計(jì)算非常有價(jià)值,比如可以讓每臺(tái)電腦負(fù)責(zé)一個(gè)函數(shù),然后串起來,實(shí)現(xiàn)流水化的作業(yè)等。
參考資料1、python 深入閉包
2、python 中的閉包
3、什么是閉包
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/37775.html
摘要:變量查找規(guī)則在中一個(gè)變量的查找順序是局部環(huán)境,閉包,全局,內(nèi)建閉包引用了自由變量的函數(shù)。閉包的作用閉包的最大特點(diǎn)是可以將父函數(shù)的變量與內(nèi)部函數(shù)綁定,并返回綁定變量后的函數(shù),此時(shí)即便生成閉包的環(huán)境父函數(shù)已經(jīng)釋放,閉包仍然存在。 導(dǎo)語:本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之函數(shù)篇的重點(diǎn)知識(shí)及個(gè)人心得,打算入門Python的朋友們可以來一起學(xué)習(xí)并交流。 本文重點(diǎn): 1、掌握裝飾器的本質(zhì)、功...
摘要:初步認(rèn)識(shí)裝飾器函數(shù)裝飾器用于在源代碼中標(biāo)記函數(shù),以某種方式增強(qiáng)函數(shù)的行為。函數(shù)裝飾器在導(dǎo)入模塊時(shí)立即執(zhí)行,而被裝飾的函數(shù)只在明確調(diào)用時(shí)運(yùn)行。只有涉及嵌套函數(shù)時(shí)才有閉包問題。如果想保留函數(shù)原本的屬性,可以使用標(biāo)準(zhǔn)庫中的裝飾器。 《流暢的Python》筆記本篇將從最簡單的裝飾器開始,逐漸深入到閉包的概念,然后實(shí)現(xiàn)參數(shù)化裝飾器,最后介紹標(biāo)準(zhǔn)庫中常用的裝飾器。 1. 初步認(rèn)識(shí)裝飾器 函數(shù)裝飾...
摘要:重寫內(nèi)建名字空間中的函數(shù)閉包閉包是詞法閉包的簡稱。另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。 Python 中的 Decorator(裝飾器) 是對(duì)一個(gè)函數(shù)或者方法的封裝,從而使其可以完成一些與自身功能無關(guān)的工作。 預(yù)備知識(shí) 一切皆對(duì)象 在 Python 中,所有的一切都被視為對(duì)象,任何的變量、函數(shù)、類等都是 object 的子類。因此除了變量之外,函數(shù)和類等也可以...
摘要:看了這一章,發(fā)現(xiàn)原來是裝飾器,又一新知識(shí)。期間,裝飾器會(huì)做一些額外的工作。書中介紹了模塊中的三個(gè)裝飾器。另一個(gè)是,這個(gè)裝飾器把函數(shù)結(jié)果保存了起來,避免傳入相同參數(shù)時(shí)重復(fù)計(jì)算。疊放不奇怪,裝飾器返回的就是函數(shù)或可調(diào)用對(duì)象。 在 Web 框架 Flask 中,最常看到的或許是以@app.route開頭的那行代碼。由于還是剛接觸 Flask,所以對(duì)這種語法還不熟悉。看了這一章,發(fā)現(xiàn)原來是裝飾...
摘要:閉包可以用來在一個(gè)函數(shù)與一組私有變量之間創(chuàng)建關(guān)聯(lián)關(guān)系。夾帶私貨外部變量返回的是函數(shù),帶私貨的函數(shù)支持將函數(shù)當(dāng)成對(duì)象使用的編程語言,一般都支持閉包。所以說當(dāng)你的裝飾器需要自定義參數(shù)時(shí),一般都會(huì)形成閉包。 Python中的閉包不是一個(gè)一說就能明白的概念,但是隨著你往學(xué)習(xí)的深入,無論如何你都需要去了解這么一個(gè)東西。 閉包的概念 我們嘗試從概念上去理解一下閉包。 在一些語言中,在函數(shù)中可以(嵌...
閱讀 2746·2021-10-11 10:57
閱讀 1574·2021-09-26 09:55
閱讀 1314·2021-09-06 15:11
閱讀 3454·2021-08-26 14:16
閱讀 671·2019-08-30 15:54
閱讀 541·2019-08-30 12:43
閱讀 3297·2019-08-29 16:18
閱讀 2573·2019-08-23 16:14