我正在建立一些基于Django' @permission_required
装饰器的装饰器。这些装饰器只需使用不同的参数调用permission_required装饰器。
例如:
def permission_required_ajax(perm):
return permission_required(perm, raise_exception=True)
这很好用,我有几个这样的例子。
问题在于我的装饰师完全不接受任何参数:
def special_permission():
return permission_required_ajax('special_permission')
这不起作用。当我使用@special_permission
装饰器修饰函数时,出现以下错误:
TypeError:special_permission()接受0个位置参数,但是给出了1个
我错过了什么?
答案 0 :(得分:5)
你还需要调用你的装饰工厂:
@special_permission()
def function():
# ...
@
符号产生后的表达式用作装饰器;调用装饰器,传递函数进行装饰。
换句话说,装饰器是语法糖:
def function():
# ...
special_permission()(function)
如果您不进行()
调用,则会将该函数传递给您的包装器。
或者,让装饰者接受该函数,并将其直接传递给permission_required_ajax()
调用产生的装饰器:
def special_permission(func):
return permission_required_ajax('special_permission')(func)
然后在不调用的情况下使用它(它现在是装饰器,而不是装饰器工厂):
@special_permission # no () call now
def function():
# ...
答案 1 :(得分:1)
当装饰器没有参数时,它会传递正在装饰的函数/类。当它有参数时,它首先用参数调用,然后在被装饰的函数/类中调用返回的内容。
回顾一下:
# Case 1, no arguments
@foo
def bar(): pass
将调用函数foo
传递函数bar
,然后将返回的任何内容绑定到名称bar
。
# Case 2
@foo(1, 2, 3)
def bar(): pass
函数foo
被称为传递1,2和3作为参数。然后调用foo
返回的内容,将bar
函数作为参数传递,返回的内容是绑定到名称bar
。
解决方案可能只是在special_permission
装饰器调用中添加括号...
@special_permission() # <-- note the parenthesis
def bar(): ...
或者,如果您不想在使用装饰器时添加括号,可以将其实现为:
def special_permission(f):
return permission_required_ajax('special_permission')(f)