当使用装饰器符号表示参数时,
@decorator(a, b, c)
def function(): pass
这是一种语法糖,用于编写代码时简化语法
def function(): pass
function = decorator(a, b, c)(function)
也就是说,
decorator
接受参数 a、b、c,并返回一个对象,该对象接受唯一参数
function
。
当装饰器是一个类时,这样的方式最容易理解。我将使用您的
permission_required
装饰器作为运行示例。它可以这样写:
class permission_required:
def __init__(self, permission):
self.permission = permission
def __call__(self, function):
@functools.wraps(function)
def wrapped_func(*args, **kwargs):
if not current_user.can(permission):
abort(403)
return function(*args, **kwargs)
return wrapped_func
admin_required = permission_required(Permission.ADMINISTER)
当您使用装饰器时,例如:
@permission_required(Permission.DESTRUCTIVE)
def erase_the_database():
raise NotImplemented
您需要首先实例化该类,将
Permission.DESTRUCTIVE
传递给
__init__
,然后将实例作为函数调用,并使用
erase_the_database
作为参数,这将调用
__call__
方法,构造包装函数并返回它。
按照这种方式考虑,
admin_required
应该更容易理解:它是
permission_required
类的一个尚未被调用的实例。 它基本上是一种简写形式:
@admin_required
def add_user(...): ...
不需要手动输入
@permission_required(Permission.ADMINISTER)
def add_user(...): ...
现在,按照您的方式...
def permission_required(permission):
def wrap(function):
@functools.wraps(function)
def wrapped_func(*args, **kwargs):
if not current_user.can(permission):
abort(403)
return function(*args, **kwargs)
return wrapped_func
return wrap
permission_required
返回的wrap
实际上只是另一种写法而已。因为从permission_required
中返回wrap
时,它会隐式地创建一个闭包对象,该对象可以像函数一样被调用,当你这样做时,它会调用wrap
函数。闭包对象会记住传递给permission_required
的permission
值,以便wrap
函数可以使用它。这正是我上面展示的类所做的事情。(事实上,像C++和Rust这样的编译型语言通常通过将闭包解糖成类定义来实现它们。)
请注意,wrap
函数本身也在做同样的事情!我们甚至可以进一步扩展它...
class permission_check_wrapper:
def __init__(self, function, permission):
self.function = function
self.permission = permission
functools.update_wrapper(self, function)
def __call__(self, *args, **kwargs):
if not current_user.can(permission):
abort(403)
return function(*args, **kwargs)
class permission_required:
def __init__(self, permission):
self.permission = permission
def __call__(self, function):
return permission_check_wrapper(self.permission, function)
或者我们可以使用functools.partial
来完成整个工作:
def permission_check_wrapper(*args, function, permission, **kwargs):
if not current_user.can(permission):
abort(403)
return function(*args, **kwargs)
def wrap_fn_with_permission_check(function, *, permission):
return functools.update_wrapper(
functools.partial(permission_check_wrapper,
function=function,
permission=permission),
wrapped=function)
def permission_required(permission):
return functools.partial(wrap_fn_with_permission_check,
permission=permission)
定义 @decorator(a,b,c) def foo
为 foo = decorator(a,b,c)(foo)
的美妙之处在于语言不在乎你选择哪种实现技术。