您好,登錄后才能下訂單哦!
python如何使用裝飾器?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
1、裝飾器的理解
裝飾器是將一個函數鑲嵌在另一個函數中進行重復使用的目的,不改變其結構,增加函數的使用方式,但是不用寫過多冗余的代碼;
裝飾器本質上是一個Python函數,它可以讓其他函數在不需要做任何代碼變動的前提下增加額外功能,裝飾器的返回值也是一個函數對象。
通常用到的功能:1.引入日志;2.函數執行時間統計;3.執行函數前預備處理;4.執行函數后清理功能;5.權限校驗;6.緩存
2、實現原理與通用寫法
咱們可以從一個簡單的記錄函數運行時間的簡單裝飾器,舉一反三,推導出一個通用的裝飾器寫法
import time def timer(func): ''' 記錄方法運行時間的裝飾器 :param func: 方法 :return:函數對象 ''' def deco(*args, **kwargs): startTime = time.time() f = func(*args, **kwargs) endTime = time.time() msecs = (endTime - startTime) * 1000 print("time is %d ms" % msecs) return f # 如果 func 有返回值得話,需要在此return回去,否則,默認返回值為 None,一般默認都返回 return deco @timer def test(parameter): print("test is running!") time.sleep(1) return "Returned value" # 該函數有返回值,所以需要在 裝飾器中的 deco 方法中 寫返回值 t = test('aa') print(t)
這是一個很簡單的通用的記錄時間的裝飾器,從而推導出一個通用的裝飾器寫法:
def func_name(func): # 自定義裝飾器函數名 def deco(*args, **kwargs): # 將所有參數原封不動的進行傳遞 print("在這個分割線之上寫函數運行前的操作") # -----------分割線----------- f = func(*args, **kwargs) # -----------分割線----------- print("在這個分割線之后,return之前,寫函數運行后的操作") return f # 如果 func 有返回值得話,需要在此return回去,否則,默認返回值為 None,一般默認都返回 return deco @func_name def test(parameter): # 8 print("test is running!") time.sleep(1) return "Returned value" # 該函數有返回值,所以需要在 裝飾器中的 deco 方法中 寫返回值 t = test('aa') print(t)
ok 裝飾器到此可以完事了,一般情況下都能滿足需求了,網上看那么多原理,有點兒浪費時間,我偏向實操型,實在不喜歡啰嗦那么多,就是干。
當然在開發過程中, 我們可能會遇到一些特殊情況,比如參數問題
1、給裝飾器函數代參數(通用)
2、將執行函數的參數拆分計算等(比如:1000w的數據,拆分成100份執行等)(定制)
那就按順序來
1、寫一個代參數的裝飾器
def logging(level): def wrapper(func): def inner_wrapper(*args, **kwargs): print("[{level}]: enter function {func}()".format(level=level, func=func.__name__)) return func(*args, **kwargs) return inner_wrapper return wrapper @logging(level='INFO') def say(something): print("say {}!".format(something)) # 如果沒有使用@語法,等同于 # say = logging(level='INFO')(say) @logging(level='DEBUG') def do(something): print("do {}...".format(something)) if __name__ == '__main__': say('hello') do("my work")
發現:就是在上面的通用的模板上又套了一層!!!,然后拿到里面的參數即可! so easy!!!
2、寫一個參數拆分的裝飾器,這個就稍微有點定制型了,不能像上面的一樣通用了,舉個 栗子:
def func_name(func): # 自定義裝飾器函數名 def deco(*args, **kwargs): # 將所有參數原封不動的進行傳遞 print(args[0]) f_list = [] for i in range(0,args[0],100000): print(i) f_list.append(func(i)) # f_list # 這兒應該按照既定規則,繼續對這個結果進行拼接,如果是寫文件、入庫等操作,可以不用return return f_list # 這兒如果有返回值得話,應該是 return deco @func_name def test(parameter): # 8 print("test is running!") time.sleep(1) return "Returned value" # 該函數有返回值,所以需要在 裝飾器中的 deco 方法中 寫返回值 t = test(1000000) print(t)
可以看出來,這個的定制性稍微高點,不通用,但是我們實現了我們的需求,所以,我們最應該理解并學會的是怎么用!!!
可以看出來,這個的定制性稍微高點,不通用,但是我們實現了我們的需求,所以,我們最應該理解并學會的是怎么用!!!
下面在介紹一下基于類實現的裝飾器,那問題來了,我是實戰派,我并沒有用類裝飾器的需求,所以,當個大盜吧,以后用到了不至于瞎找了!!!
裝飾器函數其實是這樣一個接口約束,它必須接受一個callable對象作為參數,然后返回一個callable對象。在Python中一般callable對象都是函數,但也有例外。只要某個對象重載了__call__()方法,那么這個對象就是callable的。
class Test(): def __call__(self): print 'call me!' t = Test() t() # call me
像__call__這樣前后都帶下劃線的方法在Python中被稱為內置方法,有時候也被稱為魔法方法。重載這些魔法方法一般會改變對象的內部行為。上面這個例子就讓一個類對象擁有了被調用的行為。
回到裝飾器上的概念上來,裝飾器要求接受一個callable對象,并返回一個callable對象(不太嚴謹,詳見后文)。
那么用類來實現也是也可以的。我們可以讓類的構造函數__init__()接受一個函數,然后重載__call__()并返回一個函數,也可以達到裝飾器函數的效果。
class logging(object): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print "[DEBUG]: enter function {func}()".format( func=self.func.__name__) return self.func(*args, **kwargs) @logging def say(something): print "say {}!".format(something)
帶參數的類裝飾器
如果需要通過類形式實現帶參數的裝飾器,那么會比前面的例子稍微復雜一點。那么在構造函數里接受的就不是一個函數,而是傳入的參數。通過類把這些參數保存起來。
然后在重載__call__方法是就需要接受一個函數并返回一個函數。
class logging(object): def __init__(self, level='INFO'): self.level = level def __call__(self, func): # 接受函數 def wrapper(*args, **kwargs): print "[{level}]: enter function {func}()".format( level=self.level, func=func.__name__) func(*args, **kwargs) return wrapper #返回函數 @logging(level='INFO') def say(something): print "say {}!".format(something)
關于python如何使用裝飾器問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。