以下是 Python 裝飾器模式 的詳細用法解析與實用示例,涵蓋函數裝飾器、類裝飾器及多層嵌套場景,幫助靈活擴展對象功能:
一、裝飾模式的核心思想
- 定義:動態地為對象添加額外職責,且不改變其原有結構。
- 優勢:避免繼承導致的類爆炸,支持運行時功能組合。
- Python特性:通過
@
語法糖簡化實現,本質是 高階函數 或 類包裝。
二、函數裝飾器實現
1. 基礎裝飾器(無參)
def logger(func): def wrapper(*args, **kwargs): print(f"開始執行: {func.__name__}") result = func(*args, **kwargs) print(f"執行結束: {func.__name__}") return result return wrapper @logger def add(a, b): return a + b print(add(2, 3)) # 輸出: # 開始執行: add # 執行結束: add # 5
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"Hello, {name}!") greet("Alice") # 輸出: # Hello, Alice! # Hello, Alice! # Hello, Alice!
三、類裝飾器實現
1. 裝飾器類(基於 __call__
方法)
class Timer: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): import time start = time.time() result = self.func(*args, **kwargs) end = time.time() print(f"{self.func.__name__} 耗時: {end - start:.2f}秒") return result @Timer def heavy_computation(n): return sum(i*i for i in range(n)) heavy_computation(10**6) # 輸出: heavy_computation 耗時: 0.12秒
2. 裝飾器類(帶參數)
class PermissionCheck: def __init__(self, role): self.role = role def __call__(self, func): def wrapper(*args, **kwargs): if self.role == "admin": return func(*args, **kwargs) else: raise PermissionError("權限不足") return wrapper @PermissionCheck(role="admin") def delete_file(filename): print(f"刪除文件: {filename}") delete_file("test.txt") # 輸出: 刪除文件: test.txt @PermissionCheck(role="user") def read_file(filename): print(f"讀取文件: {filename}") read_file("test.txt") # 拋出 PermissionError
四、多層裝飾器執行順序
裝飾器按 從下到上 的順序應用:
@decorator1 @decorator2 def my_func(): pass # 等價於: my_func = decorator1(decorator2(my_func))
示例:
def bold(func): def wrapper(): return "<b>" + func() + "</b>" return wrapper def italic(func): def wrapper(): return "<i>" + func() + "</i>" return wrapper @bold @italic def say_hello(): return "Hello" print(say_hello()) # 輸出: <b><i>Hello</i></b>
五、裝飾器的典型應用場景
- 日誌記錄與性能監控
跟蹤函數執行時間和參數。 - 權限驗證
限製接口訪問權限(如用戶角色檢查)。 - 緩存與記憶化
存儲函數結果避免重複計算:from functools import lru_cache @lru_cache(maxsize=128) def fibonacci(n): if n < 2: return n return fibonacci(n-1) + fibonacci(n-2)
- 路由注冊(Web框架)
Flask 框架的路由裝飾器:@app.route("/") def home(): return "Welcome"
- 輸入驗證與格式化
確保函數參數符合預期:def validate_int_args(func): def wrapper(*args): if all(isinstance(arg, int) for arg in args): return func(*args) else: raise ValueError("參數必須為整數") return wrapper
六、注意事項與調試技巧
- 保留元信息
使用functools.wraps
保持原函數屬性(如__name__
):from functools import wraps def debug(func): @wraps(func) def wrapper(*args, **kwargs): print(f"調用 {func.__name__}") return func(*args, **kwargs) return wrapper
- 處理帶狀態的裝飾器
類裝飾器適合需保存狀態的場景(如計數器):class Counter: 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) @Counter def example(): pass
- 避免循環裝飾
多層裝飾可能引發意外行為,需謹慎設計執行順序。
總結
Python 裝飾器模式通過 高階函數 或 類包裝 實現功能擴展,結合 @
語法糖可顯著提升代碼可讀性。合理使用裝飾器能實現以下目標:
- 代碼複用:抽離通用邏輯(如日誌、權限)。
- 關注點分離:業務代碼與輔助功能解耦。
- 動態擴展:運行時靈活組合功能模塊。
掌握裝飾器模式是編寫優雅 Python 代碼的關鍵技能!