對於已經對 閉包 或者 裝飾器有必定概念的,能夠直接經過右側標題目錄直接定位到相應段落查看所需的內容。html
裝飾器(Decorator)相對簡單,我們先介紹它:「裝飾器的功能是將被裝飾的函數看成參數傳遞給與裝飾器對應的函數(名稱相同的函數),並返回包裝後的被裝飾的函數」,聽起來有點繞,不要緊,直接看示意圖,其中 a 爲與裝飾器 @a 對應的函數, b 爲裝飾器修飾的函數,裝飾器@a的做用是:python
簡而言之:@a 就是將 b 傳遞給 a(),並返回新的 b = a(b)數組
栗子:閉包
上面使用@dobi來表示裝飾器,其等同於:qinfeng = dobi(qinfeng)
所以裝飾器本質上就是個語法糖,其做用爲簡化代碼,以提升代碼可讀性,運行上段代碼的結果爲:函數
解析過程是這樣子的:
1.python 解釋器發現@dobi,就去調用與其對應的函數( dobi 函數)
2.dobi 函數調用前要指定一個參數,傳入的就是@dobi下面修飾的函數,也就是 qinfeng()
3.dobi() 函數執行,調用 qinfeng(),qinfeng() 打印「dobi」spa
首先還得從基本概念提及,什麼是閉包呢?來看下維基上的解釋:
在計算機科學中,閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,即便已經離開了創造它的環境也不例外。因此,有另外一種說法認爲閉包是由函數和與其相關的引用環境組合而成的實體。閉包在運行時能夠有多個實例,不一樣的引用環境和相同的函數組合能夠產生不一樣的實例。
....
上面提到了兩個關鍵的地方: 自由變量 和 函數, 這兩個關鍵稍後再說。仍是得在贅述下「閉包」的意思,望文知意,能夠形象的把它理解爲一個封閉的包裹,這個包裹就是一個函數,固然還有函數內部對應的邏輯,包裹裏面的東西就是自由變量,自由變量能夠在隨着包裹處處遊蕩。固然還得有個前提,這個包裹是被建立出來的。
在經過Python的語言介紹一下,一個閉包就是你調用了一個函數A,這個函數A返回了一個函數B給你。這個返回的函數B就叫作閉包。你在調用函數A的時候傳遞的參數就是自由變量。
舉個栗子:3d
def func(name): def inner_func(age): print 'name:', name, 'age:', age return inner_func bb = func('the5fire') bb(26) # >>> name: the5fire age: 26
這裏面調用func的時候就產生了一個閉包——inner_func,而且該閉包持有自由變量——name,所以這也意味着,當函數func的生命週期結束以後,name這個變量依然存在,由於它被閉包引用了,因此不會被回收。code
另外再說一點,閉包並非Python中特有的概念,全部把函數作爲一等公民的語言均有閉包的概念。不過像Java這樣以class爲一等公民的語言中也可使用閉包,只是它得用類或接口來實現。htm
在 python 的函數內,能夠直接引用外部變量,但不能改寫外部變量,所以若是在閉包中直接改寫父函數的變量,就會發生錯誤:blog
在 python 2 中能夠在函數內使用 global 語句,但全局變量在任何語言中都不被提倡,由於它很難控制,python 3 中引入了 nonlocal 語句解決了這個問題:
Nonlocal 與 global 的區別在於 nonlocal 語句會去搜尋本地變量與全局變量之間的變量,其會優先尋找層級關係與閉包做用域最近的外部變量。
上面已經簡單演示了裝飾器的功能,事實上,裝飾器就是一種的閉包的應用,只不過其傳遞的是函數:
@makeitalic 裝飾器將函數 hello 傳遞給函數 makeitalic,函數 makeitalic 執行完畢後返回被包裝後的 hello 函數,而這個過程其實就是經過閉包實現的。@makebold 也是如此,只不過其傳遞的是 @makeitalic 裝飾過的 hello 函數,所以最後的執行結果 <b>
在 <i>
外層,這個功能若是不用裝飾器,其實就是顯式的使用閉包:
閉包的最大特色是能夠將父函數的變量與內部函數綁定,並返回綁定變量後的函數(也即閉包),此時即使生成閉包的環境(父函數)已經釋放,閉包仍然存在,這個過程很像類(父函數)生成實例(閉包),不一樣的是父函數只在調用時執行,執行完畢後其環境就會釋放,而類則在文件執行時建立,通常程序執行完畢後做用域才釋放,所以對一些須要重用的功能且不足以定義爲類的行爲,使用閉包會比使用類佔用更少的資源,且更輕巧靈活,現舉一例:假設咱們僅僅想打印出各種動物的叫聲,分別以類和閉包來實現:
能夠看到輸出結果是徹底同樣的,但顯然類的實現相對繁瑣,且這裏只是想輸出一下動物的叫聲,定義一個 Animal 類未免小題大作,並且 voice 函數在執行完畢後,其做用域就已經釋放,但 Animal 類及其實例 dog 的相應屬性卻一直貯存在內存中:
而這種佔用對於實現該功能後,則是沒有必要的。
除此以外,閉包還有不少其餘功能,好比用於封裝等,另外,閉包有效的減小了函數參數的數目,這對並行計算很是有價值,好比可讓每臺電腦負責一個函數,而後串起來,實現流水化的做業等。