python裝飾器詳解

來源:互聯網
上載者:User

標籤:wrapper   開始   現在   blog   功能   地址   fun   class   end   

原文地址77170585

簡言之,python裝飾器就是用於拓展原來函數功能的一種函數,這個函數的特殊之處在於它的傳回值也是一個函數,使用python裝飾器的好處就是在不用更改原函數的代碼前提下給函數增加新的功能。 
一般而言,我們要想拓展原來函數代碼,最直接的辦法就是侵入代碼裡面修改,例如:

import timedef func():    print("hello")    time.sleep(1)    print("world")

 

這是我們最原始的的一個函數,然後我們試圖記錄下這個函數執行的總時間,那最簡單的做法就是:

#原始侵入,篡改原函數import timedef func():    startTime = time.time()    print("hello")    time.sleep(1)    print("world")    endTime = time.time()    msecs = (endTime - startTime)*1000    print("time is %d ms" %msecs)

 

但是如果你的Boss在公司裡面和你說:“小祁,這段代碼是我們公司的核心代碼,你不能直接去改我們的核心代碼。”那該怎麼辦呢,我們仿照裝飾器先自己試著寫一下:

#避免直接侵入原函數修改,但是生效需要再次執行函數import timedef deco(func):    startTime = time.time()    func()    endTime = time.time()    msecs = (endTime - startTime)*1000    print("time is %d ms" %msecs)def func():    print("hello")    time.sleep(1)    print("world")if __name__ == ‘__main__‘:    f = func    deco(f)#只有把func()或者f()作為參數執行,新加入功能才會生效    print("f.__name__ is",f.__name__)#f的name就是func()    print()    #func()

 

這裡我們定義了一個函數deco,它的參數是一個函數,然後給這個函數嵌入了計時功能。然後你可以拍著胸脯對老闆說,看吧,不用動你原來的代碼,我照樣拓展了它的函數功能。 
然後你的老闆有對你說:“小祁,我們公司核心代碼地區有一千萬個func()函數,從func01()到func1kw(),按你的方案,想要拓展這一千萬個函數功能,就是要執行一千萬次deco()函數,這可不行呀,我心疼我的機器。” 
好了,你終於受夠你老闆了,準備辭職了,然後你無意間聽到了裝飾器這個神器,突然發現能滿足你閆博士的要求了。 
我們先實現一個最簡陋的裝飾器,不使用任何文法糖和進階文法,看看裝飾器最原始的面貌:

#既不需要侵入,也不需要函數重複執行import timedef deco(func):    def wrapper():        startTime = time.time()        func()        endTime = time.time()        msecs = (endTime - startTime)*1000        print("time is %d ms" %msecs)    return wrapper@decodef func():    print("hello")    time.sleep(1)    print("world")if __name__ == ‘__main__‘:    f = func #這裡f被賦值為func,執行f()就是執行func()    f()

 

這裡的deco函數就是最原始的裝飾器,它的參數是一個函數,然後傳回值也是一個函數。其中作為參數的這個函數func()就在返回函數wrapper()的內部執行。然後在函數func()前面加上@deco,func()函數就相當於被注入了計時功能,現在只要調用func(),它就已經變身為“新的功能更多”的函數了。 
所以這裡裝飾器就像一個注入符號:有了它,拓展了原來函數的功能既不需要侵入函數內更改代碼,也不需要重複執行原函數。

#帶有參數的裝飾器import timedef deco(func):    def wrapper(a,b):        startTime = time.time()        func(a,b)        endTime = time.time()        msecs = (endTime - startTime)*1000        print("time is %d ms" %msecs)    return wrapper@decodef func(a,b):    print("hello,here is a func for add :")    time.sleep(1)    print("result is %d" %(a+b))if __name__ == ‘__main__‘:    f = func    f(3,4)    #func()

 

然後你滿足了Boss的要求後,Boss又說:“小祁,我讓你拓展的函數好多可是有參數的呀,有的參數還是個數不定的那種,你的裝飾器搞的定不?”然後你嘿嘿一笑,深藏功與名!

#帶有不定參數的裝飾器import timedef deco(func):    def wrapper(*args, **kwargs):        startTime = time.time()        func(*args, **kwargs)        endTime = time.time()        msecs = (endTime - startTime)*1000        print("time is %d ms" %msecs)    return wrapper@decodef func(a,b):    print("hello,here is a func for add :")    time.sleep(1)    print("result is %d" %(a+b))@decodef func2(a,b,c):    print("hello,here is a func for add :")    time.sleep(1)    print("result is %d" %(a+b+c))if __name__ == ‘__main__‘:    f = func    func2(3,4,5)    f(3,4)    #func()

 

最後,你的老闆說:“可以的,小祁,我這裡一個函數需要加入很多功能,一個裝飾器怕是搞不定,裝飾器能支援多個嘛” 
最後你就把這段代碼丟給了他:

#多個裝飾器import timedef deco01(func):    def wrapper(*args, **kwargs):        print("this is deco01")        startTime = time.time()        func(*args, **kwargs)        endTime = time.time()        msecs = (endTime - startTime)*1000        print("time is %d ms" %msecs)        print("deco01 end here")    return wrapperdef deco02(func):    def wrapper(*args, **kwargs):        print("this is deco02")        func(*args, **kwargs)        print("deco02 end here")    return wrapper@deco01@deco02def func(a,b):    print("hello,here is a func for add :")    time.sleep(1)    print("result is %d" %(a+b))if __name__ == ‘__main__‘:    f = func    f(3,4)    #func()‘‘‘this is deco01this is deco02hello,here is a func for add :result is 7deco02 end heretime is 1003 msdeco01 end here‘‘‘

 

多個裝飾器執行的順序就是從最後一個裝飾器開始,執行到第一個裝飾器,再執行函數本身。

盜用評論裡面一位童鞋的例子:

def dec1(func):      print("1111")      def one():          print("2222")          func()          print("3333")      return one  def dec2(func):      print("aaaa")      def two():          print("bbbb")          func()          print("cccc")      return two  @dec1  @dec2  def test():      print("test test")  test()  

 

輸出:

aaaa  1111  2222  bbbb  test test  cccc  3333

 

裝飾器調用順序

裝飾器是可以疊加使用的,那麼這是就涉及到裝飾器調用順序了。對於Python中的”@”文法糖,裝飾器的調用順序與使用 @ 文法糖聲明的順序相反。

在這個例子中, addFunc(3, 8) = deco_1(deco_2(addFunc(3, 8))) 。

參考:Python 裝飾器:http://python.jobbole.com/82344/

python裝飾器詳解

相關文章

聯繫我們

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