昨天我有發一篇跟python中裝飾器相關的一些介紹,在今天我又整理了一些漏掉的功能還有其他人的一些提問,還沒看過裝飾器基本介紹的可以回去看一下裝飾器與閉包的文章喔~
python中的閉包&裝飾器 提高程式碼品質的神器
許多人的副程式都會有其他參數輸入,所以在wrapper
函數中應該也要有參數傳入,但如果副程式中的參數不同,但要使用同一個裝飾器該怎麼辦呢?這時候我們可以請出萬用參數*args,**kwargs
。其實這個萬用參數的用法也有許多眉角,但本文只介紹此參數在裝飾器的用途。*args
和**kwargs
就是python中用於傳遞可變數量參數的特殊語法。在wrapper
函數中設定輸入的參數為*args
和**kwargs
就可以不管被裝飾的函式使用的參數量以及參數名稱等。具體用法如下:
from time import time
def timing(func):
def wrapper(*args,**kwargs):
start=time()
result = func(*args,**kwargs)
end=time()
print(f"used time: {end-start}, result:{result}")
return wrapper
@timing
def sumfunc(s=100000):
for i in range(s):
s+=i
return s
sumfunc(s=100000)
# used time: 0.005526542663574219, result:5000050000
我們可以看到,當sumfunc()
中有參數傳入後,如果wrapper
沒有參數設定的話就會噴error,所以如果要被裝飾的副程式有需要傳入參數時,請記得在wrapper()
中加入*args,**kwargs
。
如果一個富城是要使用多個裝飾器可以嗎,當然可以!在使用多個裝飾器時要注意的是裝飾器的順序,以下列程式舉例:
from time import time
def timing(func):
def wrapper(*args,**kwargs):
start=time()
result = func(*args,**kwargs)
end=time()
print(f"used time: {end-start}, result:{result}")
return wrapper
def printfinish(func):
def wrapper(*args,**kwargs):
func(*args,**kwargs)
print(f"Code finish!")
return wrapper
@printfinish #後執行此裝飾器
@timing #先執行此裝飾器
def sumfunc(s=100000):
for i in range(s):
s+=i
return s
sumfunc(s=100000)
上面程式我們加了另一個裝飾器式程式執行完後會print出Code finish!的字串,我們可以注意到比較下面的@timing會先被執行,接著再執行@printfinish,也就是說越下面的裝飾器會先被執行,上面的裝飾器會被後執行。另外一個副程式可以被不限數量的裝飾器裝飾喔!
在類別中我們也會使用許多副程式(在類別中被稱為方法),在類別中方法使用裝飾器的用途也很簡單,在類別外定義裝飾器(定義裝飾器的程式區塊要在定義類別的區塊前面),然後正常裝飾方法就好了!範例如下:
def printname(func):
def wrapper(*args,**kwargs):
func(*args,**kwargs)
print(f"This function is {func.__name__}")
return wrapper
class Myclass:
@printname
def __init__(self):
pass
@printname
def hi(self):
pass
abc = Myclass()
abc.hi()
# This function is __init__
# This function is hi
昨天的文章有一些不完整的部分,今天再將他補齊,希望各位可以更理解裝飾器的用法!
另外我今天有看到其他大大的文章,我認為他比我的詳細很多orz,各位也可以去看看他的文章,我會在底下放上連結。也感謝這篇文章讓我學到更多。
DAY09-搞懂Python的裝飾器