装饰链
Decorator chain
我正在构建一些基于 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() takes 0 positional arguments but 1 was given
我错过了什么?
您还需要致电您的装饰工厂:
@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():
# ...
装饰器参数的工作原理
当装饰器没有参数时,它会传递给正在装饰的 function/class。当它有参数时,它首先用参数调用,然后返回的任何东西然后用 function/class 被装饰调用。
回顾一下:
# 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
returns 将 bar
函数作为参数传递,它 returns 绑定到名称 bar
.
针对您的情况
一个解决方案可能只是在 special_permission
装饰器调用中添加括号...
@special_permission() # <-- note the parenthesis
def bar(): ...
或者,如果您不喜欢在装饰器的使用中添加括号,它可以实现为:
def special_permission(f):
return permission_required_ajax('special_permission')(f)
我正在构建一些基于 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() takes 0 positional arguments but 1 was given
我错过了什么?
您还需要致电您的装饰工厂:
@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():
# ...
装饰器参数的工作原理
当装饰器没有参数时,它会传递给正在装饰的 function/class。当它有参数时,它首先用参数调用,然后返回的任何东西然后用 function/class 被装饰调用。
回顾一下:
# 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
returns 将 bar
函数作为参数传递,它 returns 绑定到名称 bar
.
针对您的情况
一个解决方案可能只是在 special_permission
装饰器调用中添加括号...
@special_permission() # <-- note the parenthesis
def bar(): ...
或者,如果您不喜欢在装饰器的使用中添加括号,它可以实现为:
def special_permission(f):
return permission_required_ajax('special_permission')(f)