裝飾器執行的基本原理
Python裝飾器在程序運行過程中遵循獨特的執行邏輯,其核心特性體現在模塊加載階段的即時執行。通過示例7-2的registration.py 模塊,我們可以清晰觀察到裝飾器與函數執行的時序差異。
registry = []def register(func):print('running register(%s)' % func)registry.append(func) return func @register
def f1(): print('running f1()')@register
def f2(): print('running f2()')def f3(): print('running f3()')def main():print('running main()')print('registry ->', registry)f1(); f2(); f3()if __name__ == '__main__': main()
關鍵執行時序分析
模塊加載階段
當模塊被導入(import registration)或作為腳本運行時,裝飾器會立即執行
輸出顯示裝飾器注冊過程發生在main函數之前:
running register(<function f1 at 0x100631bf8>)
running register(<function f2 at 0x100631c80>)
函數執行階段
被裝飾函數僅在顯式調用時執行
main函數中調用f1/f2時才會輸出:
running f1()
running f2()
running f3()
裝飾器與函數的執行對比
執行階段 | 裝飾器行為 | 函數行為 |
---|---|---|
模塊加載時 | 立即執行(注冊函數) | 僅保存函數定義 |
顯式調用時 | 無額外操作 | 執行函數體 |
實際應用中的注意事項
模塊組織建議
裝飾器應獨立模塊定義(如utils/decorators.py )
示例中的同模塊定義僅用于演示
裝飾器返回值規范
通常應返回新包裝函數:
def logged(func): @wraps(func) def wrapper(*args, **kwargs): print("Calling", func.name) return func(*args, **kwargs) return wrapper
Web框架中的典型應用
路由注冊模式
routes = []def route(url):def decorator(func):routes.append((url, func))return func return decorator @route("/home")
def home(): ...
性能監控裝飾器
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):start = time.time() result = func(*args, **kwargs)print(func.name, "took", time.time()-start, "s") return result return wrapper
最佳實踐總結
時序控制
利用模塊加載時的裝飾器執行特性實現自動注冊
通過延遲執行保證函數調用的靈活性
設計模式
結合functools.wraps 保持函數元數據
使用閉包實現狀態保持(如計數器裝飾器)
調試技巧
通過打印裝飾器執行日志定位初始化問題
使用pdb.set_trace() 在裝飾器內部設置斷點
這種模塊加載時的即時執行特性,使得裝飾器成為Python實現"元編程"的強大工具。理解其執行時序不僅有助于編寫高效代碼,更能幫助開發者設計出符合Pythonic規范的模塊化系統。