站長資訊網
        最全最豐富的資訊網站

        深入了解Python裝飾器函數

        本篇文章給大家帶來了關于python的相關知識,其中主要整理了裝飾器函數的相關問題,包括了裝飾器的形成過程、本質與功能、進階與優化等等內容,下面一起來看一下,希望對大家有幫助。

        深入了解Python裝飾器函數

        推薦學習:python

        假如我寫了一個函數 f

        def f():     print('hello')

        之后我想知道這段函數執行所要的時間,這好辦,我只要將代碼改為如下就行

        import time def f():     start = time.time()   #獲取程序執行開始的時間     print('hello')     end = time.time()     #獲取程序執行結束的時間     print(end - start)    #得出函數f執行所要時間  f()

        但之后我有寫了無數個函數f2,f3……fn,我想知道每個函數執行所需要的時間,那么如果都像上面一樣改,豈不是很鬧心?還是不行,因為這樣實在是太麻煩了。那怎么辦呢?于是靈機一動,寫了一個timer函數。。。

        import time def timer(func):     start = time.time()     func()     print(time.time() - start)  def f():     print('hello')   def f2():     print('xorld')  timer(f) timer(f2)

        這樣看起來是不是簡單多啦?不管我們寫了多少個函數都可以調用這個計時函數來計算函數的執行時間

        但是如果我只想用原來的方式f1(),f2(),fn()調用了這個函數,函數在原本執行輸出的結果不變的前提下還可以增加計算時間的功能,而不是調用timer(f),timer(f2)才能計算時間,這該怎么辦呢?

        看了下面的裝飾器函數你就會知道如何解決這個問題



        一、裝飾器 —— 形成過程

        以下就是解決上面問題的代碼的簡單版:

        import time  def f():     print('hello')  def timer(func):     def inner():         start = time.time()         func()         print(time.time() - start)     return inner  f = timer(f) f()

        還是這句話我只想用原來的方式f1(),f2(),fn()調用了這個函數,函數在原本執行輸出的結果不變的前提下還可以增加計算時間的功能,但我還是要在函數 f 執行前寫 f = timer(f)在這一串代碼,是不是覺得礙眼?python的開發者也覺得礙眼,所以python的開發者就為我們提供了一句語法糖來解決這個問題!



        二、裝飾器 —— 初識語法糖

        用@timmer代替f = timer(f),這就是一句語法糖。

        import time def timer(func):     def inner():         start = time.time()         func()         print(time.time() - start)     return inner  @timer   #==> 寫著這句話就相當于執行了f = timer(f) def f():     print('hello')   f()


        三、裝飾器 ——本質與功能

        1、本質

        裝飾器的本質就是一個閉包函數

        2、功能

        在不修改原函數及其調用方式的情況下對原函數功能進行擴展

        四、裝飾器 —— 裝飾帶參數,返回值的裝飾器

        • 1、裝飾帶一個參數的函數

        剛才我們寫的裝飾器都是裝飾不帶參數的函數,現在要裝飾一個帶參數的函數怎么辦呢?

        import time def timer(func):     def inner(a):         start = time.time()         func(a)         print(time.time() - start)     return inner  @timer def f(a):     print(a)  f('hello')
        • 2、裝飾多個帶有不同參數但無返回值的函數

        其實裝飾帶參的函數并不是什么難事,但假如你有兩個函數,需要傳遞的參數不一樣呢,比如 函數func1有兩個參數func1(a ,b),函數func 2只有一個參數func2(a), 且它們都想用這個裝飾器裝飾,做到計算函數執行時間?這怎么辦呢?那就用下面代碼。

        import time def timer(func):     def inner(*args,**kwargs):         start = time.time()         re = func(*args,**kwargs)         print(time.time() - start)         return re     return inner  @timer   #==> func1 = timer(func1) def func1(a,b):     print('in func1')  @timer   #==> func2 = timer(func2) def func2(a):     print('in func2 and get a:%s'%(a))     return 'fun2 over'  func1('aaaaaa','bbbbbb') print(func2('aaaaaa'))  輸出結果: in func1 0.0 in func2 and get a:aaaaaa 0.0 fun2 over
        • 3、裝飾多個帶有不同參數且有返回值的函數

        現在參數的問題已經完美的解決了,可是如果你的函數是有返回值的呢?用上面的代碼你就拿不到返回值了那究竟要如何解決這個問題呢?那就看下面的代碼吧!

        import time def timer(func):     def inner(*args,**kwargs):         start = time.time()         re = func(*args,**kwargs)         print(time.time() - start)         return re     return inner  @timer   #==> func2 = timer(func2) def func2(a):     print('in func2 and get a:%s'%(a))     return 'fun2 over'  func2('aaaaaa') print(func2('aaaaaa'))  輸出結果: in func2 and get a:aaaaaa 0.0 in func2 and get a:aaaaaa 0.0 fun2 over
        • 4、多個裝飾器裝飾同一個函數

        有些時候,我們也會用到多個裝飾器裝飾同一個函數的情況。

        ef wrapper1(func):   #func ----- f     def inner1():         print('wrapper1 ,before func')         func()         print('wrapper1 ,after func')     return inner1  def wrapper2(func):     def inner2():         print('wrapper2 ,before func')         func()         print('wrapper2 ,after func')     return inner2  @wrapper2       #f = wrapper2(f) ----->> wrapper2(inner1)  == inner2 @wrapper1       #f = wrapper1(f) = inner def f():     print('in f') f()    #===>>inner2 #多個裝飾器裝飾同一個函數  輸出結果: wrapper2 ,before func wrapper1 ,before func in f wrapper1 ,after func wrapper2 ,after func


        五、裝飾器 —— 裝飾器進階與優化

        • 1、帶參數的裝飾器

        上面那個裝飾器已經非常beautiful了,但是還有一個問題,如果我給代碼中無數個函數都加了@timer這個語法糖,如果之后我又不想用它了那豈不是又要每個去將它注釋,沒日沒夜忙活3天?豈不是特別麻煩,為了使裝飾器不用時能夠更好的回收而不是一個一個去注釋或者刪除 我們引入帶參數的裝飾器概念

        ''' 為了使裝飾器不用時能夠更好的回收而不是一個一個去注釋或者刪除 我們引入帶參數的裝飾器概念 '''  import time '''FLAGE的目的是用它控制裝飾器的開關, 那么當我們不用的時候就不要一個一個去注釋只需將True改為False就行'''  FLAGE = True def timmer_out(flag):     def timmer(func):         def inner(*args,**kwargs):             if flag:                 start = time.time()                 ret = func(*args,**kwargs)                 end = time.time()                 print(end - start)                 return ret             else:                 ret = func(*args, **kwargs)                 return ret         return inner     return timmer @timmer_out(FLAGE)  #timmer_out(FLAGE) # 也相當于執行  timmer_out(FLAGE)--->>返回timmer———————>>@timmer(wahaha = timmer(wahaha)) def wahaha():     time.sleep(0.1)         #不休息的話函數執行的太快難以計算時間     print('wahahahahahaha')  wahaha()  @timmer_out(FLAGE) def erguotou():     time.sleep(0.1)         #不休息的話函數執行的太快難以計算時間     print('erguotoutoutou')  erguotou()  輸出結果: wahahahahahaha 0.10152268409729004 erguotoutoutou 0.10795140266418457
        • 2、防止函數必要信息失效

        ''' print(wahaha.__name__)      #查看字符串格式的函數名 print(wahaha.__doc__)       #查看一個函數的注釋 ''' #下面用__name__查看holiday的函數名  from functools import wraps def wrapper(func):     @wraps(func)            #加在最內層函數正上方     def inner(*args,**kwargs):         print('在被裝飾的函數執行之前做的事')         ret = func(*args,**kwargs)         print('在被裝飾的函數執行之后做的事')         return ret     return inner  @wrapper        #holiday = wrapper(holiday) def holiday(day):     '''     這是一個放假通知     :param day:     :return:     '''     print('全體放假%s天'%day)     return '好開心'  print(holiday.__name__) print(holiday.__doc__) ''' 結果是inner和None 但我們想要的是打印holiday的字符串格式的函數名和函數的注釋這時該怎么辦? 解決方法就是  from functools import wraps 使用語法是@wraps(被裝飾的函數名) '''  輸出結果: holiday      這是一個放假通知     :param day:     :return:


        六、裝飾器 —— 裝飾原則

        • 1、開放封閉原則

        1.對原函數的功能擴展是開放的

        為什么要對功能擴展開放呢?

            對于任何一個程序來說,不可能在設計之初就已經想好了所有的功能并且未來不做任何更新和修改。所以我們必須允許后來擴展、添加新功能。

        2.對修改是封閉的

        為什么要對修改封閉呢?

        就像我們剛剛提到的,因為我們寫的一個函數,很有可能在其他地方已經被導入使用了,如果這個時候我們對其進行了修改,很有可能影響其他已經正在使用該函數的代碼。

        裝飾器就完美遵循了這個開放封閉原則。這就是學裝飾器的初衷



        小結:

        • 1、裝飾器的固定格式(模板)

        #格式一  def timer(func):     def inner(*args,**kwargs):         '''執行函數之前要做的'''         re = func(*args,**kwargs)         '''執行函數之后要做的'''         return re     return inner  #格式二  from functools import wraps  def deco(func):     @wraps(func) #加在最內層函數正上方     def wrapper(*args,**kwargs):         return func(*args,**kwargs)     return wrapper

        推薦學習:python

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 日韩精品人妻系列无码专区免费 | 国产在线精品一区二区夜色| 久久亚洲精精品中文字幕| 国产精品hd免费观看| 91精品国产综合久久婷婷| 午夜精品久久久久久中宇| 久久久久久一区国产精品| 88国产精品无码一区二区三区 | 亚洲av永久无码精品秋霞电影影院| 国产成人无码精品久久久久免费| 91探花福利精品国产自产在线 | 亚洲中文久久精品无码ww16| 国内精品久久久久久久coent| 欧美精品国产一区二区| 1000部精品久久久久久久久| 亚洲AV乱码久久精品蜜桃| 最新在线精品国自av| 亚洲国产人成精品| 日韩精品一区二区三区影院| 精品国产日韩亚洲一区| 成人精品一区二区三区在线观看| 国产精品久久久久无码av| 精品国产第一国产综合精品| 久久久久无码精品国产不卡| 中文字幕精品一区二区三区视频| 四库影院永久四虎精品国产| 亚洲第一永久AV网站久久精品男人的天堂AV| 精品国产不卡一区二区三区| 国产福利电影一区二区三区,亚洲国模精品一区 | 国产精品久久久福利| 国产精品久久久久久影院| 国产欧美久久久精品| 国产精品你懂的| 国产精品久久成人影院| 久久精品国产亚洲麻豆| 午夜精品在线观看| 国产福利电影一区二区三区久久久久成人精品综合 | 亚洲一区精品中文字幕| 国产精品户外野外| 精品无码久久久久久久久久 | 久久精品成人一区二区三区|