欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          深入了解Python裝飾器函數(shù)

          本篇文章給大家?guī)砹岁P(guān)于python的相關(guān)知識,其中主要整理了裝飾器函數(shù)的相關(guān)問題,包括了裝飾器的形成過程、本質(zhì)與功能、進(jìn)階與優(yōu)化等等內(nèi)容,下面一起來看一下,希望對大家有幫助。

          深入了解Python裝飾器函數(shù)

          推薦學(xué)習(xí):python

          假如我寫了一個函數(shù) f

          def f():     print('hello')

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

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

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

          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)

          這樣看起來是不是簡單多啦?不管我們寫了多少個函數(shù)都可以調(diào)用這個計時函數(shù)來計算函數(shù)的執(zhí)行時間

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

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



          一、裝飾器 —— 形成過程

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

          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()調(diào)用了這個函數(shù),函數(shù)在原本執(zhí)行輸出的結(jié)果不變的前提下還可以增加計算時間的功能,但我還是要在函數(shù) f 執(zhí)行前寫 f = timer(f)在這一串代碼,是不是覺得礙眼?python的開發(fā)者也覺得礙眼,所以python的開發(fā)者就為我們提供了一句語法糖來解決這個問題!



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

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

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


          三、裝飾器 ——本質(zhì)與功能

          1、本質(zhì)

          裝飾器的本質(zhì)就是一個閉包函數(shù)

          2、功能

          在不修改原函數(shù)及其調(diào)用方式的情況下對原函數(shù)功能進(jìn)行擴(kuò)展

          四、裝飾器 —— 裝飾帶參數(shù),返回值的裝飾器

          • 1、裝飾帶一個參數(shù)的函數(shù)

          剛才我們寫的裝飾器都是裝飾不帶參數(shù)的函數(shù),現(xiàn)在要裝飾一個帶參數(shù)的函數(shù)怎么辦呢?

          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、裝飾多個帶有不同參數(shù)但無返回值的函數(shù)

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

          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'))  輸出結(jié)果: in func1 0.0 in func2 and get a:aaaaaa 0.0 fun2 over
          • 3、裝飾多個帶有不同參數(shù)且有返回值的函數(shù)

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

          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'))  輸出結(jié)果: in func2 and get a:aaaaaa 0.0 in func2 and get a:aaaaaa 0.0 fun2 over
          • 4、多個裝飾器裝飾同一個函數(shù)

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

          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 #多個裝飾器裝飾同一個函數(shù)  輸出結(jié)果: wrapper2 ,before func wrapper1 ,before func in f wrapper1 ,after func wrapper2 ,after func


          五、裝飾器 —— 裝飾器進(jìn)階與優(yōu)化

          • 1、帶參數(shù)的裝飾器

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

          ''' 為了使裝飾器不用時能夠更好的回收而不是一個一個去注釋或者刪除 我們引入帶參數(shù)的裝飾器概念 '''  import time '''FLAGE的目的是用它控制裝飾器的開關(guān), 那么當(dāng)我們不用的時候就不要一個一個去注釋只需將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) # 也相當(dāng)于執(zhí)行  timmer_out(FLAGE)--->>返回timmer———————>>@timmer(wahaha = timmer(wahaha)) def wahaha():     time.sleep(0.1)         #不休息的話函數(shù)執(zhí)行的太快難以計算時間     print('wahahahahahaha')  wahaha()  @timmer_out(FLAGE) def erguotou():     time.sleep(0.1)         #不休息的話函數(shù)執(zhí)行的太快難以計算時間     print('erguotoutoutou')  erguotou()  輸出結(jié)果: wahahahahahaha 0.10152268409729004 erguotoutoutou 0.10795140266418457
          • 2、防止函數(shù)必要信息失效

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


          六、裝飾器 —— 裝飾原則

          • 1、開放封閉原則

          1.對原函數(shù)的功能擴(kuò)展是開放的

          為什么要對功能擴(kuò)展開放呢?

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

          2.對修改是封閉的

          為什么要對修改封閉呢?

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

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



          小結(jié):

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

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

          推薦學(xué)習(xí):python

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號