当参数以装饰符号给出时,
@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 # TBD: should we even have this?
首先实例化该类,将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 隐式创建一个闭包对象。它可以像函数一样被调用,当你调用它时调用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) 的美妙之处在于,该语言并不关心您选择这几种实现技术中的哪一种。