在使用裝飾器的過程中片酝,我們有時候會遇到這樣的一個問題:
我有一個裝飾器 & 我有一個函數(shù)。裝飾器的某一個參數(shù)需要在我使用函數(shù)的時候動態(tài)輸入绽榛,又或者我不能改變這個函數(shù)的情況下需要增加參數(shù)表來額外增加一些功能嗓节。
例如在Django定時任務(wù)這篇文章的最后我提到repeat
關(guān)鍵字參數(shù)來控制函數(shù)的運(yùn)行周期臼节,這種時候我們該如何實(shí)現(xiàn)呢接剩?
Solution
以上面文章提到的@background()
裝飾器為例(邏輯部分略過切厘,只解析參數(shù))。
可以這樣實(shí)現(xiàn)
from functools import wraps
def background(*, schedule):
def dont_care_name(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
repeat = kwargs.pop("repeat")
# do something with repeat
except KeyError:
pass
return func(*args, **kwargs)
return wrapper
# do something with schedule
return dont_care_name
其他都是細(xì)枝末節(jié)懊缺,重要的是疫稿,我們在獲取函數(shù)參數(shù)的那一層函數(shù)里嘗試截取repeat
這個關(guān)鍵字參數(shù)。使得無論這個參數(shù)存在與否都不會影響到func()
的執(zhí)行鹃两。
- 這一功能好處在于遗座,如果我有一個通用裝飾器。那么只需要一點(diǎn)小小的修改俊扳,就既兼容了以前的代碼途蒋,又增加了新的功能。并且函數(shù)使用起來就像從未發(fā)生改變過一樣馋记。壞處是:如果你的代碼對速度要求苛刻到一點(diǎn)點(diǎn)的扣時間優(yōu)化号坡,那么這種寫法會讓你的運(yùn)行速度多上幾毫秒。(但既然要求速度抗果,何不用Go呢,笑)