免费编程软件「python+pycharm」
链接:https://pan.quark.cn/s/48a86be2fdc0
一、装饰器初体验:给函数穿"外套"
想象你有一件普通白T恤(原始函数),现在想给它加上图案(额外功能)却不改变衣服本身。Python装饰器就像这件"魔法外套",能动态为函数添加功能而不修改原代码。
1.1 最简单的装饰器
def simple_decorator(func):
def wrapper():
print("外套前襟:添加日志")
func()
print("外套后背:记录耗时")
return wrapper
@simple_decorator
def say_hello():
print("Hello World!")
say_hello()
输出结果:
外套前襟:添加日志
Hello World!
外套后背:记录耗时
这个例子展示了装饰器的核心机制:@simple_decorator相当于say_hello = simple_decorator(say_hello),将原函数包裹在wrapper中。
1.2 处理带参数的函数
当被装饰函数需要参数时,用args和*kwargs实现万能适配:
def param_decorator(func):
def wrapper(args, **kwargs):
print(f"准备调用{func.name},参数:{args}, {kwargs}")
return func(args, **kwargs)
return wrapper
@param_decorator
def add(a, b, c=0):
return a + b + c
print(add(1, 2, c=3)) # 输出:准备调用add,参数:(1, 2), {'c': 3} \n 6
二、装饰器进阶:解决三大痛点
2.1 保留函数元信息
直接使用装饰器会丢失原函数的name、doc等信息,用functools.wraps修复:
from functools import wraps
def safe_decorator(func):
@wraps(func)
def wrapper(args, **kwargs):
"""这是包装函数的文档"""
print("安全检查通过")
return func(args, **kwargs)
return wrapper
@safe_decorator
def calculate(x):
"""计算平方"""
return x ** 2
print(calculate.name) # 输出:calculate(而非wrapper)
print(calculate.doc) # 输出:计算平方(而非包装函数的文档)
2.2 带参数的装饰器
当需要为不同函数配置不同参数时(如日志级别、缓存时间),使用三层嵌套结构:
def configurable_decorator(level="INFO"):
def decorator(func):
@wraps(func)
def wrapper(args, **kwargs):
print(f"[{level}] 调用函数: {func.name}")
return func(args, **kwargs)
return wrapper
return decorator
@configurable_decorator(level="DEBUG")
def fetch_data():
return "数据获取成功"
fetch_data() # 输出:[DEBUG] 调用函数: fetch_data
2.3 多个装饰器叠加
装饰器执行顺序遵循"从下往上装饰,从上往下执行"原则:
def decor1(func):
def wrapper():
print("装饰器1前")
func()
print("装饰器1后")
return wrapper
def decor2(func):
def wrapper():
print("装饰器2前")
func()
print("装饰器2后")
return wrapper
@decor1
@decor2
def target():
print("目标函数执行")
target()
"""
输出:
装饰器1前
装饰器2前
目标函数执行
装饰器2后
装饰器1后
"""
三、实战场景:打造企业级工具库
3.1 性能监控装饰器
自动统计函数执行时间并生成可视化报告:
import time
from functools import wraps
def performance_monitor(func):
@wraps(func)
def wrapper(args, **kwargs):
start = time.perf_counter()
result = func(args, **kwargs)
duration = time.perf_counter() - start
# 实际项目中可集成Prometheus等监控系统
print(f"⏱️ {func.__name__} 执行耗时: {duration:.4f}秒")
return result
return wrapper
@performance_monitor
def complex_calculation(n):
return sum(i*i for i in range(n))
complex_calculation(1000000) # 输出:⏱️ complex_calculation 执行耗时: 0.1234秒
3.2 缓存装饰器(Memoization)
对重复计算结果进行缓存,特别适合递归函数:
def cache_decorator(func):
cache = {}
@wraps(func)
def wrapper(n):
if n not in cache:
cache[n] = func(n)
print(f"💾 缓存命中缺失,计算并存储结果 for {n}")
else:
print(f"🎯 缓存命中 for {n}")
return cache[n]
return wrapper
@cache_decorator
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # 第二次调用fibonacci(5)等会直接从缓存读取
3.3 权限验证装饰器
在Web开发中验证用户权限的经典实现:
def role_required(required_role):
def decorator(func):
@wraps(func)
def wrapper(user, args, **kwargs):
if user.get("role") != required_role:
raise PermissionError(f"需要{required_role}权限")
return func(user, args, **kwargs)
return wrapper
return decorator
测试用例
admin = {"role": "admin", "name": "Alice"}
guest = {"role": "guest", "name": "Bob"}
@role_required("admin")
def delete_user(user, user_id):
print(f"{user['name']} 删除了用户 {user_id}")
try:
delete_user(guest, 123) # 抛出PermissionError
except PermissionError as e:
print(e) # 输出:需要admin权限
四、高级技巧:装饰器工厂与类装饰器
4.1 动态配置的装饰器工厂
根据运行时参数生成不同行为的装饰器:
def retry_decorator(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_decorator(max_attempts=5, delay=2)
def unstable_api_call():
import random
if random.random() < 0.7:
raise ConnectionError("模拟网络故障")
return "成功获取数据"
print(unstable_api_call()) # 可能需要多次重试
4.2 类装饰器实现
当需要维护状态时,类装饰器比函数更合适:
class CallCounter:
def init(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"📊 函数 {self.func.__name__} 已被调用 {self.count} 次")
return self.func(*args, **kwargs)
@CallCounter
def greet(name):
print(f"Hello, {name}!")
greet("Alice") # 输出:📊 函数 greet 已被调用 1次 \n Hello, Alice!
greet("Bob") # 输出:📊 函数 greet 已被调用 2次 \n Hello, Bob!
五、企业级封装:通用工具库设计
将常用装饰器封装成可配置的Python包:
my_decorators/
├── init.py
├── core.py # 基础装饰器实现
├── config.py # 默认配置
└── utils.py # 辅助工具
core.py示例:
from functools import wraps
import time
from .config import DEFAULT_CACHE_SIZE
def timing(func):
"""基础性能监控装饰器"""
@wraps(func)
def wrapper(args, **kwargs):
start = time.time()
result = func(args, **kwargs)
print(f"⏱️ {func.name} executed in {time.time()-start:.4f}s")
return result
return wrapper
def cached(max_size=DEFAULT_CACHE_SIZE):
"""可配置大小的缓存装饰器"""
cache = {}
def decorator(func):
@wraps(func)
def wrapper(args):
if args in cache:
return cache[args]
result = func(args)
if len(cache) >= max_size:
cache.popitem() # 简单LRU实现
cache[args] = result
return result
return wrapper
return decorator
使用示例:
from my_decorators.core import timing, cached
@timing
@cached(max_size=100)
def expensive_computation(x):
return sum(i*i for i in range(x))
print(expensive_computation(10000)) # 首次计算较慢
print(expensive_computation(10000)) # 第二次直接从缓存读取
六、最佳实践与避坑指南
性能考量:装饰器中的操作会影响所有被装饰函数,避免在wrapper中做耗时操作
异常处理:确保装饰器正确传播异常,避免静默失败
文档规范:为装饰器编写清晰的docstring,说明其行为和参数
测试覆盖:特别测试装饰器叠加、参数传递等边界情况
类型提示:使用Python 3.5+的类型注解提升可维护性:
from typing import Callable, Any, TypeVar
F = TypeVar('F', bound=Callable[..., Any])
def type_safe_decorator(func: F) -> F:
@wraps(func)
def wrapper(args, *kwargs) -> Any:
# 类型安全的实现
return func(*args, **kwargs)
return wrapper # type: ignore[return-value]
七、总结与展望
装饰器作为Python最强大的特性之一,其应用场景远不止于此。随着异步编程的普及,async装饰器、基于描述符的更复杂装饰器等高级用法正在涌现。掌握装饰器的核心思想——"在不修改原函数的情况下扩展功能",将使你的代码更加优雅、可维护且易于扩展。
建议从简单场景开始实践,逐步尝试封装自己的装饰器工具库。记住:好的装饰器应该像空气一样存在——使用时感受不到它的存在,但离开它代码将变得笨重不堪。