目录
- 一、装饰器的本质
- 二、最简单的装饰器示例
- 三、带参数函数的装饰器
- [四、使用 functools.wraps(重要)](#四、使用 functools.wraps(重要))
- 五、带参数的装饰器(高级)
- 六、类装饰器
- 七、多个装饰器
- 八、装饰器的常见应用场景
-
- [1 日志记录](#1 日志记录)
- [2 性能统计](#2 性能统计)
- [3 权限控制](#3 权限控制)
- [4 缓存(非常经典)](#4 缓存(非常经典))
- [5 重试机制](#5 重试机制)
- [6 Web框架(最常见)](#6 Web框架(最常见))
- 九、装饰器在大型项目中的作用
- 十、装饰器执行流程(面试经典)
- 十一、装饰器结构总结
- 十二、一张完整结构图
Python3 中的装饰器(Decorator)是一种非常重要的语法特性,本质上是对函数或类进行"包装"的一种机制 。它允许你在不修改原函数代码的情况下,动态地给函数增加功能。
装饰器在 Web框架、日志系统、权限控制、缓存、性能统计 等场景中非常常见。
一、装饰器的本质
一句话理解:
装饰器 = 接收函数 → 返回新函数 的函数。
数学表达:
decorator(func) -> new_func
使用装饰器语法:
python
@decorator
def foo():
pass
等价于:
python
foo = decorator(foo)
二、最简单的装饰器示例
示例:函数执行前后打印日志
python
def decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
@decorator
def say_hello():
print("Hello")
say_hello()
输出:
函数执行前
Hello
函数执行后
执行流程:
say_hello = decorator(say_hello)
调用 say_hello()
实际上调用 wrapper()
结构图:
say_hello()
↓
wrapper()
↓
func() (原函数)
三、带参数函数的装饰器
现实中函数一般都有参数。
示例
python
def decorator(func):
def wrapper(*args, **kwargs):
print("执行前")
result = func(*args, **kwargs)
print("执行后")
return result
return wrapper
@decorator
def add(a, b):
return a + b
print(add(3, 5))
输出:
执行前
执行后
8
关键点:
*args
**kwargs
保证装饰器可以适用于任何函数。
四、使用 functools.wraps(重要)
装饰器会覆盖原函数信息:
python
print(add.__name__)
会输出:
wrapper
解决方法:
python
from functools import wraps
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("执行前")
return func(*args, **kwargs)
return wrapper
作用:
保持
__name__
__doc__
__module__
等元信息。
五、带参数的装饰器(高级)
有时候装饰器本身也需要参数。
例如:
@retry(3)
@cache(10)
@timeout(5)
实现结构:
三层函数
示例:
python
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def hello():
print("hello")
hello()
输出:
hello
hello
hello
等价于:
hello = repeat(3)(hello)
结构:
repeat(n)
↓
decorator(func)
↓
wrapper()
六、类装饰器
装饰器不仅可以装饰函数,还可以装饰类。
示例:
python
def add_attr(cls):
cls.author = "Tom"
return cls
@add_attr
class Book:
pass
print(Book.author)
输出:
Tom
七、多个装饰器
python
@A
@B
@C
def f():
pass
执行顺序:
f = A(B(C(f)))
调用顺序:
A wrapper
↓
B wrapper
↓
C wrapper
↓
f
八、装饰器的常见应用场景
1 日志记录
python
def log(func):
def wrapper(*args, **kwargs):
print(f"调用函数 {func.__name__}")
return func(*args, **kwargs)
return wrapper
常见于:
- Web服务
- API调用
2 性能统计
python
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print("耗时:", time.time() - start)
return result
return wrapper
常见:
算法测试
性能分析
3 权限控制
例如 Web API:
python
def login_required(func):
def wrapper(user):
if not user.logged_in:
raise Exception("请登录")
return func(user)
return wrapper
Flask / FastAPI 中非常常见。
4 缓存(非常经典)
Python 自带:
functools.lru_cache
示例:
python
from functools import lru_cache
@lru_cache(maxsize=128)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
作用:
动态规划
缓存计算结果
5 重试机制
例如网络请求:
python
def retry(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
try:
return func(*args, **kwargs)
except:
pass
raise Exception("失败")
return wrapper
return decorator
6 Web框架(最常见)
例如 Flask
python
@app.route("/home")
def home():
return "hello"
@app.route 就是装饰器。
作用:
URL → 函数映射
九、装饰器在大型项目中的作用
在大型项目(如 AI / Web / 后端)中,装饰器常用于:
| 作用 | 示例 |
|---|---|
| 日志 | log decorator |
| 缓存 | lru_cache |
| 权限 | login_required |
| 重试 | retry |
| 计时 | timer |
| 注册机制 | register decorator |
| 路由 | Flask route |
| 配置注入 | Hydra / draccus |
例如你之前问的 draccus 里面也经常用装饰器实现:
配置注册
配置解析
十、装饰器执行流程(面试经典)
代码:
python
@decorator
def f():
pass
执行顺序:
1 定义 f
2 执行 decorator(f)
3 返回 wrapper
4 f = wrapper
5 调用 f() 实际执行 wrapper()
十一、装饰器结构总结
最通用模板
python
from functools import wraps
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
# before
result = func(*args, **kwargs)
# after
return result
return wrapper
十二、一张完整结构图
@decorator
def func()
↓
decorator(func)
↓
wrapper
↓
func = wrapper
↓
调用 func()
↓
wrapper()
↓
原函数