Python 装饰器深度解析:从基础到高级应用
引言
装饰器是 Python 中最强大且优雅的特性之一。它允许我们在不修改函数源代码的情况下,扩展或修改函数的行为。本文将从基础到高级,系统地介绍 Python 装饰器的原理和应用。
一、装饰器基础
1.1 什么是装饰器
装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。
def my_decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
@my_decorator
def say_hello():
print("你好!")
say_hello()
# 输出:
# 函数执行前
# 你好!
# 函数执行后
1.2 带参数的装饰器
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"你好,{name}!")
greet("张三")
# 输出 3 次:你好,张三!
二、常用装饰器模式
2.1 计时装饰器
import time
from functools import wraps
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 耗时: {end - start:.4f}秒")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
return "完成"
result = slow_function()
# 输出:slow_function 耗时: 1.0012秒
2.2 缓存装饰器
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 使用缓存,性能大幅提升
print(fibonacci(100)) # 几乎瞬间完成
2.3 权限检查装饰器
def require_auth(func):
@wraps(func)
def wrapper(*args, **kwargs):
user = kwargs.get('user')
if not user or not user.is_authenticated:
raise PermissionError("需要登录")
return func(*args, **kwargs)
return wrapper
@require_auth
def delete_user(user_id, user=None):
print(f"删除用户 {user_id}")
三、类装饰器
3.1 装饰类方法
class MathOperations:
@staticmethod
def add(x, y):
return x + y
@classmethod
def from_string(cls, string):
return cls()
@property
def value(self) -> int:
return self._value
@value.setter
def value(self, val: int):
if val < 0:
raise ValueError("值不能为负")
self._value = val
3.2 类装饰器
class CountCalls:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"调用次数: {self.count}")
return self.func(*args, **kwargs)
@CountCalls
def process_data(data):
return data * 2
process_data(5) # 调用次数: 1
process_data(10) # 调用次数: 2
四、高级应用
4.1 装饰器链
@timer
@lru_cache(maxsize=128)
def expensive_function(n):
time.sleep(0.1)
return n ** 2
# 第一次调用较慢,之后使用缓存
expensive_function(10)
expensive_function(10) # 使用缓存,几乎瞬时完成
4.2 参数化装饰器工厂
def retry(max_attempts=3, delay=1):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts - 1:
raise
print(f"尝试 {attempt + 1} 失败,{delay}秒后重试...")
time.sleep(delay)
return wrapper
return decorator
@retry(max_attempts=3, delay=2)
def unstable_api_call():
# 模拟不稳定的 API 调用
import random
if random.random() < 0.7:
raise ConnectionError("API 调用失败")
return "成功"
4.3 上下文管理装饰器
from contextlib import contextmanager
@contextmanager
def database_transaction():
print("开始事务")
try:
yield
print("提交事务")
except Exception:
print("回滚事务")
raise
with database_transaction():
print("执行数据库操作")
五、实战案例
5.1 Web 框架中的路由装饰器
class Router:
def __init__(self):
self.routes = {}
def route(self, path):
def decorator(func):
self.routes[path] = func
return func
return decorator
app = Router()
@app.route('/users')
def get_users():
return {"users": ["Alice", "Bob"]}
@app.route('/posts')
def get_posts():
return {"posts": []}
5.2 日志装饰器
import logging
from functools import wraps
def log_calls(level=logging.INFO):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
logging.log(level, f"调用 {func.__name__}")
try:
result = func(*args, **kwargs)
logging.log(level, f"{func.__name__} 成功")
return result
except Exception as e:
logging.error(f"{func.__name__} 失败: {e}")
raise
return wrapper
return decorator
@log_calls(logging.DEBUG)
def process_order(order_id):
print(f"处理订单 {order_id}")
总结
Python 装饰器是一个强大的工具,掌握它可以:
- 提高代码复用性:将通用逻辑抽离为装饰器
- 增强可读性:使用 @ 语法清晰表达意图
- 分离关注点:将核心逻辑与辅助功能分离
- 灵活扩展:不修改原函数即可添加功能
通过合理使用装饰器,可以写出更加优雅、可维护的 Python 代码。