在python中关于装饰器的主题花了几个小时之后,我仍然有两个问题。
首先;如果你有没有参数的装饰器,sytntax是这样的:
@decorator
def bye():
return "bye"
这只是一个语法糖,与此相同
bye = decorator(bye)
但如果我有一个带有参数的装饰器:
@decorator(*args)
def bye():
return "bye"
“无糖”版本如何?函数是作为参数之一传入的吗?
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 的装饰器的返回语句。我不知道这是如何工作的。主要是返回语句,我们返回原始装饰器+函数(用奇怪的语法)。有人可以详细说明吗? - 非常欢迎细节
答案 0 :(得分:3)
简单地调用带有参数的装饰器(使用该参数),以生成另一个装饰器。然后像往常一样用装饰函数作为参数调用该装饰器。所以翻译:
super()
将是:
@decorator(*args)
def bye():
return "bye"
或者你可能会发现更清楚:
bye = decorator(*args)(bye)
(当然,实际上并没有创建temp = decorator(*args)
bye = temp(bye)
变量。)
在第二期中,temp
被定义为@admin_required
的快捷方式。
答案 1 :(得分:2)
在装饰符号中给出参数时,
@decorator(a, b, c)
def function(): pass
这是写作的语法糖
def function(): pass
function = decorator(a, b, c)(function)
即,使用参数a,b,c调用decorator
,然后使用唯一参数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
实际上只是写同一件事的另一种方式。从wrap
返回permission_required
会隐式创建闭包对象。它可以像函数一样调用,当你这样做时调用wrap
。它会记住传递给permission
的{{1}}的值,以便permission_required
可以使用它。这正是我上面所展示的课程所做的。 (实际上,像C ++和Rust这样的编译语言经常通过将它们变成类似我所展示的类定义来实现闭包。)
请注意wrap
本身也做同样的事情!我们可以进一步扩展它......
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)
定义为desugar到@decorator(a,b,c) def foo
的美妙之处在于,该语言并不关心您选择的这些实现技巧中的哪一种。