Python裝飾器(Decorator)簡介

來源:互聯網
上載者:User

標籤:

Python有許多出色的語言特性,裝飾器(Decorator)便是其中一朵奇葩。先來看看一段代碼:

def deco1(f):    print ‘decorate 1‘    return fdef deco2(f):    print ‘decorate 2‘    return f
@deco1
@deco2def foo(): return ‘hello‘

儲存並執行上面的代碼,你會看到如下輸出:

decorate 2decorate 1

函數foo沒有被調用,但是deco1,deco2被按照一個順序被調用了。deco1和deco2就是裝飾器。從上面的輸出可以看出兩點:

1 裝飾器是在代碼裝載時被調用的

2 調用的順是從下到上

現在來說說裝配器到底做了什麼。看代碼:

def deco1(f):    print ‘decorate 1‘,f    return fdef deco2(f):    print ‘decorate 2‘,f    return f@deco1@deco2def foo():    return ‘hello‘

這段代碼的執行結果為:

decorate 2 <function foo at 0x00000000021F79E8>decorate 1 <function foo at 0x00000000021F79E8>

裝飾器函數的參數‘f’被列印出來,而且就是我們的函數‘foo’,可見裝飾器的參數就是被裝飾的函數。真的是這樣嗎?再來看代碼:

def wraper(n,f):    def foo1():        return ‘%s(%s)‘%(n,f())return foo1    def deco1(f):    print ‘decorate 1‘,f    return wraper(‘decorate 1‘,f)def deco2(f):    print ‘decorate 2‘,f    return wraper(‘decorate 2‘,f)@deco1@deco2def foo():    return ‘hello‘

這段代碼的執行結果為:

decorate 2 <function foo at 0x0000000002147A58>decorate 1 <function foo1 at 0x0000000002147AC8>

我覺得我現在可以總結一下了:

1 裝飾器在代碼裝載時被調用;

2 調用順序是從下到上的;

3 被裝飾函數‘foo’作為參數傳遞給第一個裝飾器‘deco2’,傳回值將作為參數傳遞給第二個裝飾器‘deco1’,然後依次向上直到最頂端的裝飾器;

4 最頂端的裝飾器的傳回值就是被裝飾以後的函數,我們暫時稱之為,也就是我們將來要執行的那個‘foo’。

 下面,來我們說說裝飾後的函數,被調用會有什麼結果,看代碼:

 

def wraper(n,f):    def foo1():        return ‘%s(%s)‘%(n,f())    return foo1def deco1(f):    print ‘decorate 1‘,f    return wraper(‘decorate 1‘,f)def deco2(f):    print ‘decorate 2‘,f    return wraper(‘decorate 2‘,f)@deco1@deco2def foo():    return ‘hello‘print foo()

這段代碼的執行結果為:

decorate 2 <function foo at 0x0000000002127A58>decorate 1 <function foo1 at 0x0000000002127AC8>decorate 1(decorate 2(hello))

不難看出,調用順序與裝飾順序剛好相反,最終函數也就是最頂端的裝飾器返回的函數最先被調用,然後依次調用到最初那個函數‘foo’。我在這裡故意規避了一個基本的事實,就是:其實最後被調用的就是頂端裝飾返回的那個函數,你必須手動在這個函數中調用前面的函數,見這裡:

return ‘%s(%s)‘%(n,f())

,才會產生調用連的效果。所以裝飾器並不會幫你完成所有的事情,他給了你充分的自由。說的這裡,你們要問了(如果你有足夠的好奇心):‘裝飾器能帶參數嗎’。答案是能,見下面的代碼:

 

def wraper(n,f):    def foo1():        return ‘%s(%s)‘%(n,f())    return foo1def deco(n):    def deco1(f):        print n,f        return wraper(n,f)    return deco1@deco(‘decorate 1‘)@deco(‘decorate 2‘)def foo():    return ‘hello‘print foo()

這段代碼的執行結果為:

decorate 2 <function foo at 0x0000000002117AC8>decorate 1 <function foo1 at 0x0000000002117B38>decorate 1(decorate 2(hello))

哇,和之前的結果一模一樣,代碼還被簡化了不少。這是怎麼回事呢,我來簡單解釋下,函數‘deco’不是裝飾器,他只是一個返回裝飾器的函數,當你把它放到裝飾符號‘@‘後面時,python的文法起了一個美妙的作用,他會先調用這個函數,然後用傳回值值作為裝飾器。

大概就是這樣啦,文法大師也許會描述的更詳細更專業。源碼狂人還可能深入到python的C代碼裡尋找成因。不過,作為一個有理智的好青年我們就點到為止吧。

下次,我們再來掰扯一下,裝飾器都可以變出哪些戲法吧。洗洗睡了。

 

Python裝飾器(Decorator)簡介

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.