函数(四)---装饰器
1. 什么是装饰器?
装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。装饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或可调用对象。
如果有一个名为decorate的装饰器(如下代码),
def decorate(func): def wrapper(): print('wrapper 函数开始执行') start_time = time.perf_counter() func() end_time = time.perf_counter() print(f'函数的运行时间为:{end_time - start_time}') print('wrapper 函数结束') return wrapper
则:
def for_loop(): print('for_loop函数开始执行') for i in range(1000): pass print('for_loop 函数结束') new_for = decorate(for_loop) #wrapper() new_for()
等价于:
@decorate def for_loop(): print('for_loop函数开始执行') for i in range(1000): pass print('for_loop 函数结束') for_loop()
上述两种写法结果一样,函数执行完之后得到的for_loop不一定是原来那个for_loop()函数,而是decorate(for_loop)返回的函数。
为了确认被装饰的函数会被替换,请看上边以下示例的控制台会话。
import time def decorate(func): def wrapper(): print('wrapper 函数开始执行') start_time = time.perf_counter() func() end_time = time.perf_counter() print(f'函数的运行时间为:{end_time - start_time}') print('wrapper 函数结束') return wrapper #decorate返回wrapper函数对象 @decorate #使用decorate装饰for_loop def for_loop(): print('for_loop函数开始执行') for i in range(100000): pass print('for_loop 函数结束') for_loop() #调用for_loop,其实会运行wrapper """ 运行结果: wrapper 函数开始执行 for_loop函数开始执行 for_loop 函数结束 函数的运行时间为:0.002172199999999999 wrapper 函数结束 """ print(for_loop) #发现for_loop 是wrapper的引用 # 运行结果:<function decorate.<locals>.wrapper at 0x01989580>
严格来说,装饰器只是语法糖。如前所示,装饰器可以像常规的可调用对象那样调用,其参数是另一个函数。
综上,装饰器的两大特性
1. 能把被装饰的函数替换成其他函数。
2. 装饰器在加载模块时立即执行。
2. 带有参数的装饰器
如果被修饰的函数带有参数,则装饰器中应该也放入一个参数, 且这个参数应该作为里层函数的参数进行传递。因为装饰器函数最终返回的是装饰器中的函数对象, 等价于被装饰的函数。
import time def decorate(func): def wrapper(number): print('wrapper 函数开始执行') start_time = time.perf_counter() func(number) end_time = time.perf_counter() print(f'函数的运行时间为:{end_time - start_time}') print('wrapper 函数结束') return wrapper #decorate返回wrapper函数对象 @decorate #使用decorate装饰for_loop def for_loop(number): print('for_loop函数开始执行') for i in range(number): pass print('for_loop 函数结束') for_loop(100000) #调用for_loop,其实会运行wrapper """ 运行结果: wrapper 函数开始执行 for_loop函数开始执行 for_loop 函数结束 函数的运行时间为:0.002172199999999999 wrapper 函数结束 """
2. 带有可变参数的装饰器
import time def decorate(func): def wrapper(*args): start_time = time.perf_counter() func(*args) end_time = time.perf_counter() print(f'函数的运行时间为:{end_time - start_time}') return wrapper #decorate返回wrapper函数对象 @decorate def welcome(*args): name, age = args if age >= 18: print(f'hello {name}, 你已成年') else: print(f' hello {name}, 你未成年') welcome('Elsa', 19) """ 运行结果: hello Elsa, 你已成年 函数的运行时间为:2.1300000000001873e-05 """
import time def decorate(func): def wrapper(*args, **kwargs): start_time = time.perf_counter() func(*args, **kwargs) end_time = time.perf_counter() print(f'函数的运行时间为:{end_time - start_time}') return wrapper #decorate返回wrapper函数对象 @decorate def info(*args, **kwargs): name, gender = args print(f"姓名:{name}\n性别:{gender}\n爱好:{kwargs['hobby']}") info('Elsa', 19, hobby = '乒乓球') """ 运行结果: 姓名:Elsa 性别:19 爱好:乒乓球 函数的运行时间为:2.3700000000001498e-05 """
3. 装饰器嵌套
def decorate1(func): def inner1(): print('running decorate1') func() return inner1 def decorate2(func): def inner2(): print('running decorate2') func() return inner2 @decorate1 @decorate2 def say_hi(): print('hello') """ 执行结果: running decorate1 running decorate2 hello """