本质
装饰器是一个接受函数作为参数、返回新函数的可调用对象(通常是闭包)。它用于在不修改原函数代码的情况下,增加额外功能。
适用场景
1. 日志记录
def log(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log
def greet(name):
print(f"Hello {name}")
2. 执行时间统计 / 性能分析
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__} took {time.time()-start:.4f}s")
return result
return wrapper
@timer
def heavy_computation():
time.sleep(1)
3. 权限校验 / 认证
def login_required(func):
def wrapper(user, *args, **kwargs):
if not user.get('is_authenticated'):
raise PermissionError("请先登录")
return func(user, *args, **kwargs)
return wrapper
@login_required
def view_profile(user):
print("查看个人资料")
4. 缓存 / 记忆化(Memoization)
@lru_cache(maxsize=128)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
5. 重试机制
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(times):
try:
return func(*args, **kwargs)
except Exception as e:
if i == times - 1:
raise e
print(f"Retry {i+1}")
return wrapper
return decorator
@retry(times=5)
def unstable_api_call():
# 可能失败的操作
pass
6. 事务管理(数据库)
def wrapper(*args, **kwargs):
try:
result = func(*args, **kwargs)
db.commit()
return result
except Exception:
db.rollback()
raise
return wrapper
7. 路由注册(Web框架)
def route(path):
def decorator(func):
app[path] = func
return func
return decorator
@route('/home')
def home():
return "Welcome home"
总结对比
| 特性 | 闭包 | 装饰器 |
|---|---|---|
| 核心 | 函数+引用的外部变量 | 接受函数返回函数的闭包 |
| 目的 | 封装状态、延迟计算、函数工厂 | 增强函数、横切关注点 |
| 何时用 | 需要“带状态的函数” | 需要在不改源码情况下添加功能 |
| 典型 | 计数器、惰性求值 | 日志、计时、权限、缓存 |
简单判断:
- 想创建一个“携带配置”的函数 → 闭包
- 想为多个函数统一增加功能 → 装饰器