您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關python裝飾器如何使用,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
裝飾者模式是常用的軟件設計模式之一。通過此設計模式,我們能夠在不修改任何底層代碼情況下,給已有對象賦予新的職責。python中可以用裝飾器簡單地實現裝飾者模式。
1.1 將函數作為參數傳遞
在C/C++中,函數指針可以將函數作為參數傳遞給另一函數。而在python中,函數也是對象的一種,函數可以被引用,也可直接作為參數傳入函數,以及作為容器對象的元素。python中可以采用如下方法實現裝飾者模式:
#!/usr/bin/env python3.6 # -*- coding: utf-8 -*- def add(x, y): result = x+y return result def log(func): def wrapper(*args, **kwargs): result = func(*args) print(func.__name__,'has been called\n') return result return wrapper if __name__ == '__main__': print(log(add)(1,2))
上述代碼中,log函數以需要被裝飾的函數作為參數,并返回函數對象。被返回的函數的參數為可變參數*args與**kwargs(*args參數會被封裝成tuple,**kwargs參數則會被封裝成字典對象),以適應不同函數的不同參數,保證通用性。
1.2 裝飾器
上面的實現方法有些繁雜,所有調用被裝飾的函數之處的代碼,都要進行相應修改,自然不符合python簡潔易讀的特性。因此python中給出相應語法糖來增加可讀性和易用性,那便是“裝飾器”。
from functools import wraps def log(func): #@wraps(func) def wrapper(*args, **kwargs): result = func(*args) print(func.__name__,'has been called') return result return wrapper #等價于add = log(add) @log def add(x, y): result = x+y return result if __name__ == '__main__': print(add(1,2)) print(add.__name__)
運行情況如下:
>>print(add(1,2)) add has been called 3 >>print(add.__name__) wrapper
但上述方法亦有缺陷,原函數add的元數據(比如名字、文檔字符串、注解和參數簽名)會丟失。為避免缺陷,任何時候你定義裝飾器的時候,都應該使用functools庫中的@wraps裝飾器來注解底層包裝函數(代碼中注釋部分)。@wraps有一個重要特征是它能讓你通過屬性 __wrapped__ 直接訪問被包裝函數。
改進后運行情況:
>>print(add(1,2)) add has been called 3 >>print(add.__name__) add
1.3 解除裝飾器
當裝飾器已經作用于某函數,而你想撤銷它,那么可以訪問 __wrapped__屬性來訪問原始函數
orig_add = add.__wrapped__ orig_add(1,2)
但若使用了多個裝飾器, __wrapped__屬性會變得不可控,應盡量避免使用。
若有如下代碼:
#!/usr/bin/env python3.6 # -*- coding: utf-8 -*- import functools import time def metric(func): @functools.wraps(func) def wrapper(*args,**kv): print('Decorator1') f = func(*args,**kv) return f return wrapper def logging(func): @functools.wraps(func) def wrapper(*args,**kv): print('Decorator2') f = func(*args,**kv) return f return wrapper @metric @logging def normalize(name): sName = name[0:1].upper() + name[1:].lower() print(sName) if __name__ == '__main__': normalize('heLlO') normalize.__wrapper__('')
運行情況如下:
>>normalize('helLo') Decorator1 Decorator2 Hello >>normalize.__wrapped__('world') Decorator2 World
1.4 定義帶參數的裝飾器
from functools import wraps def log(text): def decorator(func): @wraps(func) def wrappering(*args,**kv): print('%s %s():'%(text,func.__name__)) return func(*args,**kv) return wrappering return decorator @log('run') def normalize(name): sName = name[0:1].upper() + name[1:].lower() print(sName)
裝飾器函數可以帶參數,最外層的函數會將參數傳給內層的裝飾器函數,即wrappering函數是可以使用log的傳入參數的。
裝飾器處理過程與下面是等價的:
normalize = log('run')(normalize)
關于python裝飾器如何使用就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。