您好,登錄后才能下訂單哦!
這篇文章主要介紹了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、功能
在不修改原函數及其調用方式的情況下對原函數功能進行擴展
剛才我們寫的裝飾器都是裝飾不帶參數的函數,現在要裝飾一個帶參數的函數怎么辦呢?
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')
其實裝飾帶參的函數并不是什么難事,但假如你有兩個函數,需要傳遞的參數不一樣呢,比如 函數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
現在參數的問題已經完美的解決了,可是如果你的函數是有返回值的呢?用上面的代碼你就拿不到返回值了那究竟要如何解決這個問題呢?那就看下面的代碼吧!
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
有些時候,我們也會用到多個裝飾器裝飾同一個函數的情況。
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
上面那個裝飾器已經非常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
''' 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裝飾器函數怎么使用”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“Python裝飾器函數怎么使用”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。