簡析Python的閉包和裝飾器

來源:互聯網
上載者:User
什麼是裝飾器?
裝飾器(Decorator)相對簡單,咱們先介紹它:“裝飾器的功能是將被裝飾的函數當作參數傳遞給與裝飾器對應的函數(名稱相同的函數),並返回封裝後的被裝飾的函數”,聽起來有點繞,沒關係,直接看,其中 a 為與裝飾器 @a 對應的函數, b 為裝飾器修飾的函數,裝飾器@a的作用是:

簡而言之:@a 就是將 b 傳遞給 a(),並返回新的 b = a(b)

栗子:

上面使用@dobi來表示裝飾器,其等同於:qinfeng = dobi(qinfeng)
因此裝飾器本質上就是個文法糖,其作用為簡化代碼,以提高代碼可讀性,運行上段代碼的結果為:

解析過程是這樣子的:
1.python 解譯器發現@dobi,就去調用與其對應的函數( dobi 函數)
2.dobi 函數調用前要指定一個參數,傳入的就是@dobi下面修飾的函數,也就是 qinfeng()
3.dobi() 函數執行,調用 qinfeng(),qinfeng() 列印“dobi”

什麼是閉包?
首先還得從基本概念說起,什麼是閉包呢?來看下維基上的解釋:
在電腦科學中,閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,是引用了自由變數的函數。這個被引用的自由變數將和這個函數一同存在,即使已經離開了創造它的環境也不例外。所以,有另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。閉包在運行時可以有多個執行個體,不同的引用環境和相同的函數組合可以產生不同的執行個體。
....
上面提到了兩個關鍵的地方: 自由變數 和 函數, 這兩個關鍵稍後再說。還是得在贅述下“閉包”的意思,望文知意,可以形象的把它理解為一個封閉的包裹,這個包裹就是一個函數,當然還有函數內部對應的邏輯,包裹裡面的東西就是自由變數,自由變數可以在隨著包裹到處遊盪。當然還得有個前提,這個包裹是被建立出來的。
在通過Python的語言介紹一下,一個閉包就是你調用了一個函數A,這個函數A返回了一個函數B給你。這個返回的函數B就叫做閉包。你在調用函數A的時候傳遞的參數就是自由變數。
舉個栗子:

def func(name):  def inner_func(age):    print 'name:', name, 'age:', age  return inner_funcbb = func('the5fire')bb(26) # >>> name: the5fire age: 26

這裡面調用func的時候就產生了一個閉包——inner_func,並且該閉包持有自由變數——name,因此這也意味著,當函數func的生命週期結束之後,name這個變數依然存在,因為它被閉包引用了,所以不會被回收。

另外再說一點,閉包並不是Python中特有的概念,所有把函數做為一等公民的語言均有閉包的概念。不過像Java這樣以class為一等公民的語言中也可以使用閉包,只是它得用類或介面來實現。

nonlocal 語句
在 python 的函數內,可以直接引用外部變數,但不能改寫外部變數,因此如果在閉包中直接改寫父函數的變數,就會發生錯誤:

在 python 2 中可以在函數內使用 global 語句,但全域變數在任何語言中都不被提倡,因為它很難控制,python 3 中引入了 nonlocal 語句解決了這個問題:

Nonlocal 與 global 的區別在於 nonlocal 語句會去搜尋本地變數與全域變數之間的變數,其會優先尋找層級關係與閉包範圍最近的外部變數。

閉包與裝飾器
上面已經簡單示範了裝飾器的功能,事實上,裝飾器就是一種的閉包的應用,只不過其傳遞的是函數:

@makeitalic 裝飾器將函數 hello 傳遞給函數 makeitalic,函數 makeitalic 執行完畢後返回被封裝後的 hello 函數,而這個過程其實就是通過閉包實現的。@makebold 也是如此,只不過其傳遞的是 @makeitalic 裝飾過的 hello 函數,因此最後的執行結果 外層,這個功能如果不用裝飾器,其實就是顯式的使用閉包:

閉包的作用
閉包的最大特點是可以將父函數的變數與內建函式綁定,並返回綁定變數後的函數(也即閉包),此時即便產生閉包的環境(父函數)已經釋放,閉包仍然存在,這個過程很像類(父函數)產生執行個體(閉包),不同的是父函數只在調用時執行,執行完畢後其環境就會釋放,而類則在檔案執行時建立,一般程式執行完畢後範圍才釋放,因此對一些需要重用的功能且不足以定義為類的行為,使用閉包會比使用類佔用更少的資源,且更輕巧靈活,現舉一例:假設我們僅僅想列印出各類動物的叫聲,分別以類和閉包來實現:

可以看到輸出結果是完全一樣的,但顯然類的實現相對繁瑣,且這裡只是想輸出一下動物的叫聲,定義一個 Animal 類未免小題大做,而且 voice 函數在執行完畢後,其範圍就已經釋放,但 Animal 類及其執行個體 dog 的相應屬性卻一直貯存在記憶體中:

而這種佔用對於實現該功能後,則是沒有必要的。

除此之外,閉包還有很多其他功能,比如用於封裝等,另外,閉包有效減少了函數參數的數目,這對並行計算非常有價值,比如可以讓每台電腦負責一個函數,然後串起來,實現流水化的作業等。

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.