我写了一个看起来像这个
的装饰器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
然后()
是可选的。那么,我如何将这个“可选”功能封装到装饰器中,以便我可以装饰我的装饰器以允许没有参数?
答案 0 :(得分:3)
我实际上最近写了一篇关于此事的blog post - 至少,我认为它解决了你想要做的事情。对于后代,这是我想出的:
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
顺便说一句,在试图弄清楚如何去做的过程中,我得出的结论是,这是几乎总是比必要更复杂的事情之一; - )
答案 1 :(得分:1)
这个答案的灵感来自 Python Cookbook 的 recipe 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
并且您使用默认参数应用装饰器
然而,如果你指定了 args (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")
请注意,您需要指定关键字参数。