Python 装饰器进阶:从基础到实战
# Python 装饰器进阶:从基础到实战
装饰器是 Python 中最优雅的特性之一,它允许我们在不修改函数代码的情况下扩展其功能。本文将深入探讨装饰器的高级用法,并通过实际案例展示其强大之处。
## 装饰器基础回顾
装饰器本质上是一个接收函数作为参数并返回新函数的高阶函数。最简单的装饰器形式如下:
```python
def simple_decorator(func):
def wrapper(*args, **kwargs):
print(f"调用函数: {func.__name__}")
result = func(*args, **kwargs)
print(f"函数执行完毕")
return result
return wrapper
@simple_decorator
def greet(name):
return f"你好, {name}!"
print(greet("小明"))
```
## 带参数的装饰器
有时候我们需要装饰器接受自定义参数。这需要使用三层嵌套结构:参数层、装饰器层、包装层。
```python
def repeat(times=2):
"""重复执行装饰器"""
def decorator(func):
def wrapper(*args, **kwargs):
results = []
for _ in range(times):
result = func(*args, **kwargs)
results.append(result)
return results[-1] # 返回最后一次的结果
return wrapper
return decorator
@repeat(times=3)
def process_data(data):
print(f"处理数据: {data}")
return len(data)
result = process_data("hello")
print(f"最终结果: {result}")
```
## 类装饰器
类也可以作为装饰器,这使得我们可以更好地维护装饰器的状态。
```python
class TimerDecorator:
"""计时器类装饰器"""
def __init__(self, precision=2):
self.precision = precision
def __call__(self, func):
import time
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
elapsed = round(end - start, self.precision)
print(f"{func.__name__} 执行时间: {elapsed}秒")
return result
return wrapper
@TimerDecorator(precision=4)
def slow_operation():
import time
time.sleep(0.1)
return "完成"
slow_operation()
```
## 保留函数元数据
使用装饰器时,原始函数的元信息(如 __name__、__doc__)会被覆盖。Python 提供了 functools.wraps 来解决这个问题。
```python
import functools
def log_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"[LOG] 调用 {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_decorator
def calculate(x, y):
"""计算两个数的和"""
return x y
print(calculate.__name__) # 输出: calculate
print(calculate.__doc__) # 输出: 计算两个数的和
```
## 实战应用:缓存装饰器
缓存装饰器可以显著提高重复调用函数的性能,特别是对于计算密集型操作。
```python
import functools
class Memoize:
"""带超时的缓存装饰器"""
def __init__(self, ttl=60):
self.ttl = ttl # 缓存有效期(秒)
self.cache = {}
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
import time
# 创建缓存键
key = (args, frozenset(kwargs.items()))
if key in self.cache:
value, timestamp = self.cache[key]
if time.time() - timestamp < self.ttl:
print(f"[缓存命中] {func.__name__}{args}")
return value
# 计算新值
result = func(*args, **kwargs)
self.cache[key] = (result, time.time())
return result
return wrapper
@Memoize(ttl=10)
def expensive_computation(n):
"""模拟耗时计算"""
import time
print(f"执行复杂计算: {n}")
time.sleep(0.5) # 模拟耗时操作
return n ** 2
print(expensive_computation(5)) # 执行计算
print(expensive_computation(5)) # 从缓存读取
```
## 实战应用:权限验证装饰器
在 Web 开发中,权限验证是常见需求,装饰器可以优雅地实现这一功能。
```python
class AuthDecorator:
"""权限验证装饰器"""
def __init__(self, required_role):
self.required_role = required_role
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 模拟从上下文获取用户信息
user = kwargs.get('user', {'role': 'guest'})
if user['role'] != self.required_role:
raise PermissionError(
f"权限不足: 需要 {self.required_role},"
f"当前是 {user['role']}"
)
return func(*args, **kwargs)
return wrapper
@AuthDecorator(required_role='admin')
def delete_resource(resource_id, user):
"""删除资源(需要管理员权限)"""
print(f"删除资源: {resource_id}")
return True
# 测试权限验证
try:
delete_resource(123, user={'role': 'admin'}) # 成功
delete_resource(123, user={'role': 'user'}) # 失败
except PermissionError as e:
print(f"错误: {e}")
```
## 装饰器链
多个装饰器可以叠加使用,执行顺序是从下往上(从内向外)。
```python
def bold(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return f"{func(*args, **kwargs)}"
return wrapper
def italic(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return f"{func(*args, **kwargs)}"
return wrapper
@bold
@italic
def format_text(text):
return text
print(format_text("重要提示")) # 输出: 重要提示
```
## 最佳实践
1. **总是使用 functools.wraps**:保留被装饰函数的元数据
2. **保持装饰器简单**:复杂的逻辑应该分解成多个装饰器
3. **文档化装饰器**:清晰的文档字符串说明装饰器的用途
4. **考虑类装饰器**:需要维护状态时,类装饰器更合适
5. **谨慎处理异常**:装饰器不应该意外吞掉异常
## 总结
Python 装饰器是 AOP(面向切面编程)思想的优雅实现。通过装饰器,我们可以:
- 分离关注点(日志、计时、验证等)
- 提高代码复用性
- 保持核心逻辑的简洁
掌握装饰器的高级用法,将让你的 Python 代码更加优雅和高效。
