📘 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)中實現文檔或權限的自動化控制