Decorator(裝飾器) 是 Python 中很好用的一個東西,只要 @
一下就可以處理掉很多東西,其實 Decorator(裝飾器) 不難理解,而且容易使用所以在 Python 中很常使用到。不過這篇沒有要講太深,只是讓你比較容易理解與使用而已。
那麼這麼好用的東西怎麼使用呢?就讓我們自己做一個簡單的出來吧!就先來刻個計算程式執行時間的裝飾器好了,這樣可以更快的了解。首先架構為這樣(就一個資料夾裡面有個檔案而已啦,算不上架構):
decorator_test/
└── test.py
檔案內容為:
test.py
from time import time
def time_counter(func):
def wrapper(*args, **kwargs): # 習慣上會取名叫 wrapper
start = time()
result = func(*args, **kwargs)
end = time()
usage_time = (end - start)
return result, usage_time
return wrapper
# 不要括號喔
@time_counter
def star_triangle(times):
step = ""
for i in range(1, times+1, 2):
for j in range((times-i)//2):
step += " "
for j in range(i):
step += "*"
step += "\n"
return step
res = star_triangle(5000) # 5000 如果跑太久可以適當的減少它
print("Time: {:>30.24f} second".format(res[1]))
執行後的時間大概會長這樣(嗯,我沒有讓它輸出,不然很恐怖)
> Time: 3.177063703536987304687500 second
蛤,這樣就一個喔,啊它到底是怎樣出現的?
別急,把15行刪掉(@time_counter
那行),再把27行改成這樣
res = time_counter(star_triangle)(5000) # 5000 如果跑太久可以適當的減少它
應該會出現類似的結果(秒數不一樣很正常)
> Time: 3.209057331085205078125000 second
這樣懂了嗎?還記的 Day 06 講過的這些嗎?
在 Python 中,Function 的地位和 C++、Java等不同,是屬於 "First-class Citizen" (一等公民),故稱作 "First-class function" (一級函數)。
什麼是 "First-class Citizen" 呢?跟二等公民又差在哪呢?
最明顯的差別是 Python 中的 Function 可以當成參數傳遞並執行(對啦,我就是只想講這句而已,其他暫時不太重要)。
Decorator(裝飾器) 就是把@
下面的 Function 當成參數傳遞並執行了,大概就是每次呼叫 Function 都會像這樣一層一層轉換(這邊只是方便理解而已):
Step1: res = star_triangle(5000)
Step2: res = time_counter(star_triangle)(5000)
Step3: res = wrapper(5000):
Step4: res get wrapper return
因為 func
這個東西位於 time_counter
的裡面,所以同樣位於time_counter
裡面的 wrapper
不需要把它當參數也可以使用(大概就是台中市民搭公車免費,你住在北區的話,你也可以免費的意思)
啊如果裝飾器想要有參數的話怎麼辦,就再加一層變這樣
test.py
from time import time
def time_counter(func):
def wrapper(*args, **kwargs): # 習慣上會取名叫 wrapper
start = time()
result = func(*args, **kwargs)
end = time()
usage_time = (end - start)
return result, usage_time
return wrapper
def record_now_time(time_format="%Y-%m-%d %H:%M:%S"):
def decorator(func):
def wrapper(*args, **kwargs):
print(datetime.now().strftime(time_format) + " - Start function: " + func.__name__)
# __name__ 可以取得 Function 的名稱
result = func(*args, **kwargs)
print(datetime.now().strftime(time_format) + " - End function: " + func.__name__)
return result
return wrapper
return decorator
@record_now_time(time_format="%H:%M:%S")
def star_triangle(times):
step = ""
for i in range(1, times+1, 2):
for j in range((times-i)//2):
step += " "
for j in range(i):
step += "*"
step += "\n"
return step
res = star_triangle(5000) # 5000 如果跑太久可以適當的減少它
這樣執行的輸出會變這樣(最後面的print
要刪掉)
> 22:20:26 - Start function: star_triangle
> 22:20:29 - End function: star_triangle
如果想要同時使用多個裝飾器怎麼辦,就加上去啊,會變成這樣:
test.py
from time import time
def time_counter(func):
def wrapper(*args, **kwargs): # 習慣上會取名叫 wrapper
start = time()
result = func(*args, **kwargs)
end = time()
usage_time = (end - start)
return result, usage_time
return wrapper
def record_now_time(time_format="%Y-%m-%d %H:%M:%S"):
def decorator(func):
def wrapper(*args, **kwargs):
print(datetime.now().strftime(time_format) + " - Start function: " + func.__name__)
result = func(*args, **kwargs)
print(datetime.now().strftime(time_format) + " - End function: " + func.__name__)
return result
return wrapper
return decorator
@time_counter
@record_now_time(time_format="%H:%M:%S")
def star_triangle(times):
step = ""
for i in range(1, times+1, 2):
for j in range((times-i)//2):
step += " "
for j in range(i):
step += "*"
step += "\n"
return step
res = star_triangle(5000) # 5000 如果跑太久可以適當的減少它
print("Time: {:>30.24f} second".format(res[1]))
然後它就會一層一層吃上去,類似這樣:
Step1: res = star_triangle(5000)
Step2: res = record_now_time(time_format="%H:%M:%S")(star_triangle)(5000)
Step3: res = time_counter()(record_now_time)(time_format="%H:%M:%S")(star_triangle)(5000)
Step4: res = wrapper(5000):
Step5: res get wrapper return
有沒有發現到後面越來越長了,寫個裝飾器更加的簡單明瞭對吧!
Python進階技巧 (3) — 神奇又美好的 Decorator ,嗷嗚!
那麼就大概這樣,這篇是讓你在使用套件時,遇到裝飾器不會不知如何使用而已。話說其實不只 Funciton 可以變成裝飾器,Class 也可以。不過關於這個問題,我不會在下個文章講解(這是一個小坑了,真要講大概又要開幾篇來講,話說都第五天了還沒進主題)。
大家掰~掰~