📘 Python 装饰器进阶指南
一、装饰器本质
✅ 本质概念
Python 装饰器的本质是 函数嵌套 + 返回函数,它是对已有函数的增强,不修改原函数代码,使用语法糖 @decorator
实现包裹效果。
def my_decorator(func):def wrapper(*args, **kwargs):print("Before")result = func(*args, **kwargs)print("After")return resultreturn wrapper@my_decorator
def say_hello():print("Hello!")
✅ 装饰器其实是这样的调用:
say_hello = my_decorator(say_hello)
二、元数据保持:functools.wraps
❗ 问题
普通装饰器会丢失原函数的元数据,如 __name__
, __doc__
等。
✅ 解决方案:使用 functools.wraps
from functools import wrapsdef my_decorator(func):@wraps(func)def wrapper(*args, **kwargs):print("Running:", func.__name__)return func(*args, **kwargs)return wrapper
🌟 好处
- 文档自动生成工具能识别原始函数
- 保持调试友好、函数签名保留
三、反射 + 动态设置装饰器
✅ 场景:你不想在函数上一个个手动写 @装饰器
,而是运行时自动批量装饰。
示例:动态为某类中所有特定方法添加装饰器
def my_log_decorator(func):@wraps(func)def wrapper(*args, **kwargs):print(f"[LOG] {func.__name__} 被调用")return func(*args, **kwargs)return wrapperclass MyClass:def method_a(self): print("A")def method_b(self): print("B")# 动态装饰
for name in ['method_a', 'method_b']:method = getattr(MyClass, name)setattr(MyClass, name, my_log_decorator(method))obj = MyClass()
obj.method_a()
四、进阶实践:Django DRF + 动态文档装饰器
✅ 背景
使用 drf-spectacular
时,需要为 ViewSet
方法添加 @extend_schema
,但方法多、内容重复,适合动态处理。
💡 做法:定义映射 + 动态应用装饰器
from drf_spectacular.utils import extend_schema
from functools import wraps
from rest_framework import viewsetsclass SchemaModelViewSet(viewsets.ModelViewSet):schema_summary_mapping = {'list': "获取{name}列表",'retrieve': "获取单个{name}",'create': "创建{name}",'update': "更新{name}",'partial_update': "局部更新{name}",'destroy': "删除{name}"}# 动态应用装饰器
def _apply_schema_decorators():for method_name, summary_tpl in SchemaModelViewSet.schema_summary_mapping.items():if hasattr(SchemaModelViewSet, method_name):base_method = getattr(viewsets.ModelViewSet, method_name)@wraps(base_method)def dynamic_wrapper(*args, **kwargs):return base_method(*args, **kwargs)decorated = extend_schema(summary=summary_tpl.format(name="对象"))(dynamic_wrapper)setattr(SchemaModelViewSet, method_name, decorated)_apply_schema_decorators()
✅ 优点
- 方法不需要手动一个个写装饰器
- 支持格式化 summary,按模型/资源名称自动生成
- 保持方法原始签名与元数据,文档准确生成
五、进阶技巧汇总
技巧 | 说明 |
---|---|
@wraps(func) | 保持元数据,推荐用于所有自定义装饰器 |
动态装饰 | 使用 getattr + setattr 为方法动态添加装饰器 |
装饰器工厂 | 装饰器接收参数时需要多层函数嵌套 |
多重装饰 | 多个装饰器可层层嵌套处理逻辑 |
类装饰器 | __call__ 方法定义类装饰器 |
六、结语
装饰器是 Python 函数式编程的核心工具,掌握以下几点,就可以自由应对开发中的各种装饰器需求:
- 理解函数对象 & 嵌套函数原理
- 使用
wraps
保持元信息 - 动态反射结合装饰器进行自动化增强
- 在大型框架(如 Django DRF)中实现文档或权限的自动化控制