在使用裝飾器的過程中,我們有時候會遇到這樣的一個問題:
我有一個裝飾器 & 我有一個函數(shù)。裝飾器的某一個參數(shù)需要在我使用函數(shù)的時候動態(tài)輸入,又或者我不能改變這個函數(shù)的情況下需要增加參數(shù)表來額外增加一些功能。
例如在Django定時任務(wù)這篇文章的最后我提到repeat關(guān)鍵字參數(shù)來控制函數(shù)的運行周期,這種時候我們該如何實現(xiàn)呢?
Solution
以上面文章提到的@background()裝飾器為例(邏輯部分略過,只解析參數(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
其他都是細枝末節(jié),重要的是,我們在獲取函數(shù)參數(shù)的那一層函數(shù)里嘗試截取repeat這個關(guān)鍵字參數(shù)。使得無論這個參數(shù)存在與否都不會影響到func()的執(zhí)行。
- 這一功能好處在于,如果我有一個通用裝飾器。那么只需要一點小小的修改,就既兼容了以前的代碼,又增加了新的功能。并且函數(shù)使用起來就像從未發(fā)生改變過一樣。壞處是:如果你的代碼對速度要求苛刻到一點點的扣時間優(yōu)化,那么這種寫法會讓你的運行速度多上幾毫秒。(但既然要求速度,何不用Go呢,笑)