我终于弄懂了 Python 的装饰器(二)
发布于: 2020 年 07 月 09 日
此系列文档:
二、装饰器的高级用法
将参数传递给装饰函数
#它不是黑魔法,只是给包装(wrapper)传递参数:def a_decorator_passing_arguments(function_to_decorate):def a_wrapper_accepting_arguments(arg1, arg2):print("I got args! Look: {0}, {1}".format(arg1, arg2))function_to_decorate(arg1, arg2)return a_wrapper_accepting_arguments#因为当您调用装饰器返回的函数时,调用的包装器(wrapper),将参数传递给被包装器包装的函数@a_decorator_passing_argumentsdef print_full_name(first_name, last_name):print("My name is {0} {1}".format(first_name, last_name))print_full_name("Peter", "Venkman")# 输出:#I got args! Look: Peter Venkman#My name is Peter Venkman
将参数传递给装饰器
关于将参数传递给装饰器本身,您怎么认为?
因为装饰器必须接受一个函数作为参数,所以这可能会有些别扭。
因此,您不能将装饰函数的参数直接传递给装饰器。
在寻求解决方案之前,让我们写一些提醒:
#装饰器是普通函数def my_decorator(func):print("I am an ordinary function")def wrapper():print("I am function returned by the decorator")func()return wrapper# 因此,你可以调用它,而不用 "@"def lazy_function():print("zzzzzzzz")decorated_function = my_decorator(lazy_function)#输出: I am an ordinary function# 它输出了 "I am an ordinary function", 因为你只是调用了装饰器,而没有调用函数:# 这里没有什么神奇的地方,使用'@'@my_decoratordef lazy_function():print("zzzzzzzz")#outputs: I am an ordinary function
结果一样。
my_decorator
”被调用了。
因此,当您使用时@my_decorator
,您要告诉Python,通过变量来调用my_decorator
标记了的函数。
def decorator_maker():print("I make decorators! I am executed only once: ""when you make me create a decorator.")def my_decorator(func):print("I am a decorator! I am executed only when you decorate a function.")def wrapped():print("I am the wrapper around the decorated function. ""I am called when you call the decorated function. ""As the wrapper, I return the RESULT of the decorated function.")return func()print("As the decorator, I return the wrapped function.")return wrappedprint("As a decorator maker, I return a decorator")return my_decorator#让我们新建一个装饰器new_decorator = decorator_maker()#输出:#I make decorators! I am executed only once: when you make me create a decorator.#As a decorator maker, I return a decorator# 让我们装饰这个函数def decorated_function():print("I am the decorated function.")decorated_function = new_decorator(decorated_function)#输出:#I am a decorator! I am executed only when you decorate a function.#As the decorator, I return the wrapped function# 让我们调用这个函数decorated_function()#输出:#I am the wrapper around the decorated function. I am called when you call the decorated function.#As the wrapper, I return the RESULT of the decorated function.#I am the decorated function.
毫不奇怪,跟我们前边演示的内容一样。
让我们再做一次完全一样的事情,但是这次我们跳过所有讨厌的中间变量:
def decorated_function():print("I am the decorated function.")decorated_function = decorator_maker()(decorated_function)#输出:#I make decorators! I am executed only once: when you make me create a decorator.#As a decorator maker, I return a decorator#I am a decorator! I am executed only when you decorate a function.#As the decorator, I return the wrapped function.# Finally:decorated_function()#输出:#I am the wrapper around the decorated function. I am called when you call the decorated function.#As the wrapper, I return the RESULT of the decorated function.#I am the decorated function.
让我们把它变的更精简:
@decorator_maker()def decorated_function():print("I am the decorated function.")#输出:#I make decorators! I am executed only once: when you make me create a decorator.#As a decorator maker, I return a decorator#I am a decorator! I am executed only when you decorate a function.#As the decorator, I return the wrapped function.#最终:decorated_function()#输出:#I am the wrapper around the decorated function. I am called when you call the decorated function.#As the wrapper, I return the RESULT of the decorated function.#I am the decorated function.
嘿,你看到了吗?我们使用了带有“ @
”语法的函数调用!
因此,回到带有参数的装饰器。
如果我们可以使用函数即时生成装饰器,则可以将参数传递给该函数,对吗?
def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):print("I make decorators! And I accept arguments: {0}, {1}".format(decorator_arg1, decorator_arg2))def my_decorator(func):#这里传递的参数是闭包的。#如果您对封包感到不舒服,可以忽略这点。print("I am the decorator. Somehow you passed me arguments: {0}, {1}".format(decorator_arg1, decorator_arg2))#不要混淆装饰器参数和函数参数!def wrapped(function_arg1, function_arg2) :print("I am the wrapper around the decorated function.\n""I can access all the variables\n""\t- from the decorator: {0} {1}\n""\t- from the function call: {2} {3}\n""Then I can pass them to the decorated function".format(decorator_arg1, decorator_arg2,function_arg1, function_arg2))return func(function_arg1, function_arg2)return wrappedreturn my_decorator@decorator_maker_with_arguments("Leonard", "Sheldon")def decorated_function_with_arguments(function_arg1, function_arg2):print("I am the decorated function and only knows about my arguments: {0}"" {1}".format(function_arg1, function_arg2))decorated_function_with_arguments("Rajesh", "Howard")#输出:#I make decorators! And I accept arguments: Leonard Sheldon#I am the decorator. Somehow you passed me arguments: Leonard Sheldon#I am the wrapper around the decorated function.#I can access all the variables# - from the decorator: Leonard Sheldon# - from the function call: Rajesh Howard#Then I can pass them to the decorated function#I am the decorated function and only knows about my arguments: Rajesh Howard
记住它:带参数的装饰器,可以将变量作为参数:
c1 = "Penny"c2 = "Leslie"@decorator_maker_with_arguments("Leonard", c1)def decorated_function_with_arguments(function_arg1, function_arg2):print("I am the decorated function and only knows about my arguments:"" {0} {1}".format(function_arg1, function_arg2))decorated_function_with_arguments(c2, "Howard")#输出:#I make decorators! And I accept arguments: Leonard Penny#I am the decorator. Somehow you passed me arguments: Leonard Penny#I am the wrapper around the decorated function.#I can access all the variables# - from the decorator: Leonard Penny# - from the function call: Leslie Howard#Then I can pass them to the decorated function#I am the decorated function and only know about my arguments: Leslie Howard
如您所见,您可以像任何函数传递参数一样传递参数给装饰器。
您甚至可以根据需要使用*args, **kwargs
。
但是请记住,装饰器仅被调用一次,仅在Python导入脚本时。之后,您将无法动态设置参数。
当您执行“ import x”时,该函数已经被修饰,因此您无法进行任何更改。
本文首发于BigYoung小站:http://www.bigyoung.cn
划线
评论
复制
发布于: 2020 年 07 月 09 日 阅读数: 29
版权声明: 本文为 InfoQ 作者【Young先生】的原创文章。
原文链接:【http://xie.infoq.cn/article/ed1976b6acac72038b9d7c0a8】。未经作者许可,禁止转载。
Young先生
关注
Python工程师/书虫/极客/ 2020.04.22 加入
伸手摘星,即使徒劳无功,也不至于满手泥污。 欢迎大家访问我的BigYoung小站(bigyoung.cn)
评论