代码之家  ›  专栏  ›  技术社区  ›  mpen

没有争论装饰装饰?

  •  1
  • mpen  · 技术社区  · 14 年前

    我写了一个看起来像这样的装饰师

    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
    

    然后 () 是可选的。那么,如何将这个“可选”功能封装到一个decorator中,以便我可以将我的decorator修饰为不允许参数呢?

    1 回复  |  直到 14 年前
        1
  •  3
  •   David Z    14 年前

    我最近写了一篇 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
    

        2
  •  1
  •   Gabriel    3 年前

    这个答案的灵感来自Python食谱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")

    注意,您需要指定关键字参数。