从另一个装饰器创建装饰器 (python)
creating decorator out of another decorator (python)
在 python 中的装饰器主题上花了几个小时后,我仍然有两个问题。
首先;如果你有没有参数的装饰器,sytntax 是这样的:
@decorator
def bye():
return "bye"
这只是一个语法糖,与此相同
bye = decorator(bye)
但是如果我有一个带参数的装饰器:
@decorator(*args)
def bye():
return "bye"
"no-sugar" 版本怎么样?函数是否作为参数之一传入内部?
bye = decorator("argument", bye)
第二期(与第一个相关,但更实际的例子);
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_function
return wrap
def admin_required(f):
return permission_required(Permission.ADMINISTER)(f)
这里permission_required装饰器被传递给新创建的装饰器admin_required[=32的return语句=].我不知道这是怎么回事。主要是 return 语句,其中我们 returning 原始装饰器 + 函数(使用奇怪的语法)。有人可以详细说明吗? - 非常欢迎提供详细信息
带有参数的装饰器被简单地调用(带有该参数),以产生另一个装饰器。然后像往常一样以装饰函数作为参数调用该装饰器。所以翻译:
@decorator(*args)
def bye():
return "bye"
将是:
bye = decorator(*args)(bye)
或者您可能会发现更清楚:
temp = decorator(*args)
bye = temp(bye)
(当然,实际上没有创建 temp
变量。)
在您的第二期中,@admin_required
被定义为 @permission_required(Permission.ADMINISTER)
的快捷方式。
当参数以修饰符号给出时,
@decorator(a, b, c)
def function(): pass
写作的语法糖
def function(): pass
function = decorator(a, b, c)(function)
也就是说,decorator
使用参数 a、b、c 调用,然后 对象 returns 使用唯一参数调用 function
.
当装饰器是 class 时,最容易理解它的意义。我将使用您的 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?
首先实例化 class,将 Permission.DESTRUCTIVE
传递给 __init__
,然后将该实例作为函数调用,并以 erase_the_database
作为参数,调用__call__
方法,构造包装函数和 returns 它。
这样想,admin_required
应该更容易理解:它是permission_required
class的一个实例,还没有被调用。基本上是 shorthand:
@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
可以使用它。这正是我上面显示的 class 所做的。 (事实上 ,像 C++ 和 Rust 这样的编译语言通常通过将闭包脱糖到 class 定义中来实现闭包,就像我展示的那样。)
注意 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)
的美妙之处在于,该语言不关心您选择这几种实现技术中的哪一种。
在 python 中的装饰器主题上花了几个小时后,我仍然有两个问题。
首先;如果你有没有参数的装饰器,sytntax 是这样的:
@decorator
def bye():
return "bye"
这只是一个语法糖,与此相同
bye = decorator(bye)
但是如果我有一个带参数的装饰器:
@decorator(*args)
def bye():
return "bye"
"no-sugar" 版本怎么样?函数是否作为参数之一传入内部?
bye = decorator("argument", bye)
第二期(与第一个相关,但更实际的例子);
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_function
return wrap
def admin_required(f):
return permission_required(Permission.ADMINISTER)(f)
这里permission_required装饰器被传递给新创建的装饰器admin_required[=32的return语句=].我不知道这是怎么回事。主要是 return 语句,其中我们 returning 原始装饰器 + 函数(使用奇怪的语法)。有人可以详细说明吗? - 非常欢迎提供详细信息
带有参数的装饰器被简单地调用(带有该参数),以产生另一个装饰器。然后像往常一样以装饰函数作为参数调用该装饰器。所以翻译:
@decorator(*args)
def bye():
return "bye"
将是:
bye = decorator(*args)(bye)
或者您可能会发现更清楚:
temp = decorator(*args)
bye = temp(bye)
(当然,实际上没有创建 temp
变量。)
在您的第二期中,@admin_required
被定义为 @permission_required(Permission.ADMINISTER)
的快捷方式。
当参数以修饰符号给出时,
@decorator(a, b, c)
def function(): pass
写作的语法糖
def function(): pass
function = decorator(a, b, c)(function)
也就是说,decorator
使用参数 a、b、c 调用,然后 对象 returns 使用唯一参数调用 function
.
当装饰器是 class 时,最容易理解它的意义。我将使用您的 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?
首先实例化 class,将 Permission.DESTRUCTIVE
传递给 __init__
,然后将该实例作为函数调用,并以 erase_the_database
作为参数,调用__call__
方法,构造包装函数和 returns 它。
这样想,admin_required
应该更容易理解:它是permission_required
class的一个实例,还没有被调用。基本上是 shorthand:
@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
可以使用它。这正是我上面显示的 class 所做的。 (事实上 ,像 C++ 和 Rust 这样的编译语言通常通过将闭包脱糖到 class 定义中来实现闭包,就像我展示的那样。)
注意 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)
的美妙之处在于,该语言不关心您选择这几种实现技术中的哪一种。