没有参数装饰器的装饰器?
我写了一个装饰器,代码大概是这样的:
def login_required_message(*args, **kwargs):
kwargs.setdefault('message', "You must be logged in to do that.")
return _user_passes_test_message(lambda u: u.is_authenticated(), *args, **kwargs)
但是当我尝试在后面不加()
来使用它时,就会出错,除非我把它改成这样:
def login_required_message(function=None, *args, **kwargs):
kwargs.setdefault('message', "You must be logged in to do that.")
decorator = _user_passes_test_message(lambda u: u.is_authenticated(), *args, **kwargs)
if function: return decorator(function)
else: return decorator
这样的话,()
就是可选的。那么,我该怎么把这个“可选”的功能放进装饰器里,这样我就可以装饰我的装饰器,让它们可以不带参数呢?
2 个回答
这个回答的灵感来源于《Python Cookbook》的第9.6个食谱。
def mydecorator_with_opt_args(func=None, arg1="arg1-default", arg2="arg2-default"):
if func is None:
return partial(mydecorator_with_opt_args, arg1=arg1, arg2=arg2)
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Do something with {arg1} and {arg2}")
return func(*args, **kwargs)
return wrapper
使用方法:
@mydecorator_with_opt_args(arg1="arg1-set", arg2="arg2-set")
def passer():
pass
passer()
将会输出
"Do something with arg1-set and arg2-set"
@mydecorator_with_opt_args
def passer2():
pass
passer2()
将会输出
"Do something with arg1-default and arg2-default"
如果你不传参数(passer2),会发生什么呢?加上一个装饰器就像是在写 passer2 = mydecorator_with_opt_args(passer2)
,这意味着 if func is None
这一部分会被忽略,你会用默认参数来应用这个装饰器。
但是如果你传了参数(passer),加上一个装饰器就像是在写 passer = mydecorator_with_opt_args(arg1="arg1-set", arg2="arg2-set")(passer)
。
mydecorator_with_opt_args(arg1="arg1-set", arg2="arg2-set")
会返回 partial(mydecorator_with_opt_args, arg1="arg1-set", arg2="arg2-set")
,然后 partial(mydecorator_with_opt_args, arg1="arg1-set", arg2="arg2-set")(passer)
相当于 mydecorator_with_opt_args(func=passer, arg1="arg1-set", arg2="arg2-set")
。
注意,你需要指定关键字参数。
我最近写了一篇博客文章,我觉得它可能能帮到你。为了记录下来,这里是我想到的内容:
def opt_arguments(func):
def meta_wrapper(*args, **kwargs):
if len(args) == 1 and callable(args[0]):
return func(args[0])
else:
def meta_func(inner_func):
return func(inner_func, *args, **kwargs)
return meta_func
return meta_wrapper
顺便说一下,在我努力弄明白怎么做的过程中,我发现这件事几乎总是比必要的要复杂得多;-)