在我的遗留代码中,我发现了两种编写视图装饰器的方法。 第一:
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”? 或者我应该以完全不同的方式编写它?你写装饰器的方法是什么?
答案 0 :(得分:3)
这些做不同的事情。第一个是标准装饰器,即它包装一个函数并返回包装版本,在调用原始函数之前调用它时会执行一些操作。它以标准方式使用:
@require_session
def function_that_requires_session(request):
...
第二个是参数化装饰器。也就是说,装饰器本身需要一个参数 - 在这种情况下,需要确切的角色 - 因此定义需要接受一个参数,然后返回一个实际的装饰器,它与标准相同上面的版本。这就是为什么你有一个额外级别的嵌套函数。所以,这将使用这样:
@require_role(role_that_is_required)
def function_that_requires_role(request):
...
如您所见,装饰器采用了一个参数。
两者之间的另一个区别是第一个是使用手动方式将名称/文档字符串传递给修饰函数,而第二个使用functools.wraps()
。你应该做后者(虽然lvc指出,你可以将它用作装饰器,甚至更清晰)。
答案 1 :(得分:1)
处理复制文档字符串和其他元数据的常用方法是使用functools.wraps
,就像在第二个示例中一样,除了可以使用其返回值作为装饰器:
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
# do stuff
return wrapper