【问题标题】:How should I write decorators?我应该如何编写装饰器?
【发布时间】:2015-03-22 10:00:26
【问题描述】:

在我的遗留代码中,我发现了两种编写视图装饰器的方法。 第一个:

def require_session(f):
    def wrap(request, *args, **kwargs):
        if not 'username' in request.session:
            messages.warning(request,_('You have to login first before you can access this page.'))
            return redirect('/login')
        return f(request, *args, **kwargs)
    wrap.__doc__=f.__doc__
    wrap.__name__=f.__name__
    return wrap

第二个:

def require_role(role):
    def decorator(func):
        def inner_decorator(request,*args, **kwargs):
            user_role = request.session.get('role','user')
            if user_role != role:
                if user_role == 'user':
                    return redirect('/dashboard')
                else:
                    return redirect('/dashboard/list_users')
            return func(request, *args, **kwargs)
        return wraps(func)(inner_decorator)
    return decorator

哪个更好,更“pythonic”? 或者也许我应该用完全不同的方式来写它?你写装饰器的方式是什么?

【问题讨论】:

    标签: python django python-decorators


    【解决方案1】:

    它们做不同的事情。第一个是标准装饰器,即它包装一个函数并返回包装后的版本,当被调用时,它会在调用原始装饰器之前做一些事情。它以标准方式使用:

    @require_session
    def function_that_requires_session(request):
        ...
    

    第二个是参数化装饰器。也就是说,装饰器本身需要一个参数 - 在这种情况下,需要确切的角色 - 因此定义需要接受一个参数然后返回一个实际的装饰器,这与标准相同上面的版本。这就是为什么您有额外级别的嵌套函数。所以,这将是这样使用的:

    @require_role(role_that_is_required)
    def function_that_requires_role(request):
        ...
    

    如你所见,装饰器带有一个参数。

    两者之间的另一个区别是第一个是使用手动方式将名称/文档字符串传输到修饰函数,而第二个是使用functools.wraps()。你应该做后者(尽管正如 lvc 指出的那样,你可以将它用作装饰器,这更加清晰)。

    【讨论】:

      【解决方案2】:

      处理复制文档字符串和其他元数据的常用方法是使用functools.wraps,就像在您的第二个示例中一样,除了您可以将其返回值用作装饰器

      def my_decorator(func):
          @wraps(func)
          def wrapper(*args, **kwargs):
              # do stuff
      
          return wrapper
      

      【讨论】:

        猜你喜欢
        • 2021-01-28
        • 2015-03-24
        • 2010-09-15
        • 2023-03-28
        • 1970-01-01
        • 2011-04-20
        • 2012-10-28
        • 1970-01-01
        • 2014-12-31
        相关资源
        最近更新 更多