from functools import wraps
def apply_deco_from_name(f):
@wraps(f)
def wrapper(self, *args, **options):
# this code is called instead of the decorated method
# and *now* we have access to the options mapping.
name = options["name"] # or use options.pop("name") to remove it
decorated = deco(name)(f) # the same thing as @deco(name) for the function
return decorated(self, *args, **options)
return wrapper
然后在命令处理程序上使用该装饰器:
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument(
"--name",
type=str,
required=True,
)
@apply_deco_from_name
def handle(self, *_args, **options):
name = options["name"]
3条答案
按热度按时间gkl3eglg1#
您可以创建一个“元装饰器”,类似于:
然后使用元装饰器:
xmjla07d2#
当应用
@deco
装饰器时,您没有访问命令行值的权限,没有。但是您 * 可以 * 延迟应用该装饰器,直到您有访问权限为止。通过创建你自己的装饰器来实现这一点。装饰器只是一个函数,当Python解析
@decorator
和def functionname
行时,就在Python创建函数对象之后应用它;装饰器的返回值取代了被装饰的函数。那么,你需要确保的是,当命令被执行时,你的装饰器返回一个不同的函数来应用deco
装饰器**。下面是这样一个装饰者:
然后在命令处理程序上使用该装饰器:
这里发生了什么?当Python处理
@apply_deco_from_name
和def handle(...)
行时,它将其视为类内部的一个完整的函数语句。它将创建一个handle
函数对象,然后将其传递给装饰器,因此它调用apply_deco_from_name(handle)
。上面定义的装饰器返回wrapper
* 而不是 *。当Django执行这个命令处理程序时,它会调用
wrapper(command, [other arguments], name="command-line-value-for-name", [other options])
来替换它。此时代码会创建一个新的修饰版本的处理程序,它使用decorated = deco("command-line-value-for-name")(f)
*,就像Python在命令类中使用@deco("command-line-value-for-name")
* 一样。deco("command-line-value-for-name")
返回一个装饰器函数,deco("command-line-value-for-name")(f)
返回一个 Package 器。并在最后调用 Package 器。oyxsuwqo3#
你的装饰器并不一定是一个装饰器,因为你使用的是类,你可以使用mixin pattern: