在使用装饰器的过程中,我们有时候会遇到这样的一个问题:
我有一个装饰器 & 我有一个函数。装饰器的某一个参数需要在我使用函数的时候动态输入,又或者我不能改变这个函数的情况下需要增加参数表来额外增加一些功能。
例如在Django定时任务这篇文章的最后我提到repeat
关键字参数来控制函数的运行周期,这种时候我们该如何实现呢?
Solution
以上面文章提到的@background()
装饰器为例(逻辑部分略过,只解析参数)。
可以这样实现
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
其他都是细枝末节,重要的是,我们在获取函数参数的那一层函数里尝试截取repeat
这个关键字参数。使得无论这个参数存在与否都不会影响到func()
的执行。
- 这一功能好处在于,如果我有一个通用装饰器。那么只需要一点小小的修改,就既兼容了以前的代码,又增加了新的功能。并且函数使用起来就像从未发生改变过一样。坏处是:如果你的代码对速度要求苛刻到一点点的扣时间优化,那么这种写法会让你的运行速度多上几毫秒。(但既然要求速度,何不用Go呢,笑)