

01.装饰器基本概念及原理

装饰器就是在不修改函数源代码的情况下,动态地增加、修改或包装函数的行为。这为我们的代码提供了更高的可重用性和可扩展性。这篇依然使用不是很难的装饰器和非常实用的小例子来帮助理解
装饰器的原理
1 2
| # -*- coding: utf-8 -*-# @Author: Mehaei# @Date: 2023-08-09 21:39:57# @Last Modified by: Mehaei# @Last Modified time: 2023-08-09 22:43:57import time def code(): # 功能代码块 time.sleep(.1) print("func代码块执行完成")# 后面想在这个函数上增加一个耗时统计操作,# 在不改变原代码的情况下, 使用装饰器def timer_count(func): def wrapper(): st = time.time() func() print(f"{func} 执行完成, 耗时: {time.time() - st}") return wrappercode = timer_count(code)code()
|
输出
1 2 3
| func代码块执行完成 <function code at 0x10f487510> 执行完成, 耗时: 0.10348010063171387 [Finished in 0.1s]
|
上面这种写法就等于
在code函数上加语法糖 @timer_count, 直接调用code的结果是一致的,
1 2 3 4 5 6 7
| @timer_count def code(): # 功能代码块 time.sleep(.1) print("func代码块执行完成") code()
|
输出
1 2 3
| func代码块执行完成 <function code at 0x105156510> 执行完成, 耗时: 0.1029362678527832 [Finished in 0.2s]
|

02.装饰器基本格式

1 2 3 4 5 6 7 8 9 10 11 12 13
| def decorator(func): def wrapper(*args, **kwargs): # 在函数调用前做些操作 result = func(*args, **kwargs) # 在函数调用后做些操作 return result return wrapper @decorator def my_function(): # 函数体 pass
|
在上面的示例中,decorator是一个装饰器函数,它接受一个函数func作为参数,并返回一个新的函数wrapper。wrapper函数可以在调用原始函数之前和之后执行额外的操作。下面就写一些实用的小例子, 讲几种不同写法和用法的装饰器

03.函数带参数的装饰器

装饰器本身也可以接收参数,从而使其更加通用和灵活。带参数的装饰器可以用于传递配置或控制信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # 带有参数的装饰器 def decorator(func): def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper @decorator def greet(name): print(f"Hello {name}!") # 调用函数 greet("Python")
|
输出
1 2
| Hello Python! [Finished in 0.1s]
|

04.函数和装饰器都有参数

有时候,我们希望装饰器在使用时具有更多的灵活性,允许我们为装饰器本身传递关键参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| # 日志记录装饰器 def log(level): def decorator(func): def wrapper(*args, **kwargs): print(f"{level}: Calling {func.__name__}") result = func(*args, **kwargs) return result return wrapper return decorator @log(level="INFO") def add(a, b): return a + b # 调用函数 print(add(2, 3))
|
输出:
1 2 3
| INFO: Calling add 5 [Finished in 0.1s]
|
这个装饰器log接收一个等级level参数, 用于判断日志等级和记录日志

05.类装饰器

除了函数装饰器外,Python还支持类装饰器。类装饰器是一个类,它的实例可以像函数装饰器一样,接受一个函数作为参数并返回一个新的函数。这个是一个记录函数耗时操作的类装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| # 耗时记录 class Timer(object): def __init__(self, func): self.func = func # 使用call魔术方法, 实现类装饰器 def __call__(self, *args, **kwargs): st = time.time() result = self.func(*args, **kwargs) print(f"函数: {self.func.__name__} 耗时 {time.time() - st} /s") return result @Timer def slow_function(): time.sleep(.2) print(f"slow_function 执行完成") # 调用函数 slow_function()
|
输出
1 2 3
| slow_function 执行完成 函数: slow_function 耗时 0.2013709545135498 /s [Finished in 0.3s]
|

06.函数和类装饰器加参数

使用类装饰器时, 往往也需要使用参数, 差不多的写法, 来写一个重试类装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| # 重试类 class Retry(object): def __init__(self, times=5): self.times = times # 使用call魔术方法, 实现类装饰器 def __call__(self, func): def wrapper(*args, **kwargs): st = time.time() result = None for tt in range(self.times): try: result = func(*args, **kwargs) except Exception as e: print(f"执行函数: {func.__name__}/{tt}, 错误: {e}") print(f"函数: {func.__name__} 耗时 {time.time() - st} /s") return result return wrapper @Retry(times=2) def slow_function(): time.sleep(.2) raise ValueError("测试自定义的错误") print(f"slow_function 执行完成") # 调用函数 slow_function()
|
输出
1 2 3 4
| 执行函数: slow_function/0, 错误: 测试自定义的错误 执行函数: slow_function/1, 错误: 测试自定义的错误 函数: slow_function 耗时 0.408797025680542 /s [Finished in 0.5s]
|

07.多个装饰器嵌套使用

也有的时候需要多个装饰器同时使用, 因为不同装饰器可能有不同的功能, 同样一个函数或一个对象可以多个装饰器嵌套使用
1 2
| import timefrom functools import wrapsdef timer_count(func): @wraps(func) def wrapper(): st = time.time() func() print(f"{func} 执行完成, 耗时: {time.time() - st}") return wrapperdef log(func): @wraps(func) def wrapper(): st = time.time() func() print(f"{func} 写入log, 耗时: {time.time() - st}") return wrapper# code = timer_count(code)# code()@log@timer_countdef code(): # 功能代码块 time.sleep(.1) print("func代码块执行完成") code()
|
输出(没有添加@wraps装饰器的输出)
1 2 3
| func代码块执行完成 <function code at 0x10f99ebf8> 执行完成, 耗时: 0.10388422012329102 <function timer_count.<locals>.wrapper at 0x10f99ed90> 写入log, 耗时: 0.10395598411560059
|
添加了@wraps装饰器的输出
1 2 3 4
| func代码块执行完成 <function code at 0x109376620> 执行完成, 耗时: 0.10320019721984863 <function code at 0x109633bf8> 写入log, 耗时: 0.10324931144714355 [Finished in 0.2s]
|
由输出可以一眼看出, 多层装饰器嵌套使用时, 是由内层开始向外层, 逐层调用

08.这篇也完了

装饰器是Python中非常强大的工具,可以用于增强、修改或包装函数的行为。带参数的装饰器、关键参数的装饰器以及类装饰器使得我们能够更灵活地控制装饰器的行为。通过合理地运用装饰器,我们可以编写出更具可维护性和可扩展性的代码。
今日推荐
python异常处理
python类的常用魔术方法
python中的类和对象
