sca*_*one 6 python python-3.x python-decorators
在花了几个小时讨论 python 中的装饰器主题之后,我仍然有两个问题。
第一的; 如果你有没有参数的装饰器,那么 sytntax 是这样的:
@decorator
def bye():
return "bye"
Run Code Online (Sandbox Code Playgroud)
这只是一个语法糖,与此相同
bye = decorator(bye)
Run Code Online (Sandbox Code Playgroud)
但如果我有一个带有参数的装饰器:
@decorator(*args)
def bye():
return "bye"
Run Code Online (Sandbox Code Playgroud)
“无糖”版本怎么样?该函数是否作为参数之一传递到内部?
bye = decorator("argument", bye)
Run Code Online (Sandbox Code Playgroud)
第二个问题(与第一个问题相关,但更实际的例子);
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)
Run Code Online (Sandbox Code Playgroud)
这里,permission_required装饰器被传递给新创建的名为admin_required的装饰器的 return 语句。我不知道这是如何运作的。主要是 return 语句,我们返回原始装饰器+函数(以奇怪的语法)。有人可以详细说明一下吗?- 非常欢迎详细信息
当参数以装饰器表示法给出时,
@decorator(a, b, c)
def function(): pass
Run Code Online (Sandbox Code Playgroud)
它是写作的语法糖
def function(): pass
function = decorator(a, b, c)(function)
Run Code Online (Sandbox Code Playgroud)
也就是说,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)
Run Code Online (Sandbox Code Playgroud)
当你使用装饰器时,例如
@permission_required(Permission.DESTRUCTIVE)
def erase_the_database():
raise NotImplemented # TBD: should we even have this?
Run Code Online (Sandbox Code Playgroud)
您首先实例化该类,传递Permission.DESTRUCTIVE给__init__,然后将该实例作为函数调用并作为参数erase_the_database,这将调用该__call__方法,该方法构造包装的函数并返回它。
这样想admin_required应该更容易理解:它是permission_required类的一个实例,还没有被调用。基本上是为了简写:
@admin_required
def add_user(...): ...
Run Code Online (Sandbox Code Playgroud)
而不是打字
@permission_required(Permission.ADMINISTER)
def add_user(...): ...
Run Code Online (Sandbox Code Playgroud)
现在,按照你的方式...
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
Run Code Online (Sandbox Code Playgroud)
实际上只是同一件事的另一种写法。wrap从隐式返回permission_required创建一个闭包对象。它可以像函数一样被调用,当你这样做时,它会调用wrap. permission它会记住传递给的值permission_required,以便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)
Run Code Online (Sandbox Code Playgroud)
或者我们可以用以下方法完成整个工作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)
Run Code Online (Sandbox Code Playgroud)
@decorator(a,b,c) def foo定义脱糖的美妙之foo = decorator(a,b,c)(foo)处在于,该语言并不关心您选择这几种实现技术中的哪一种。