如何在 Python 中建立和使用裝飾器
了解如何在 Python 中編寫和應用裝飾器。掌握包裝函數、修改行為、處理參數、使用包裝保存元資料。
概述
裝飾器是 Python 最優雅、最強大的語法功能之一,可讓您修改函數或類別的行為,而無需永久更改其程式碼。它們廣泛用於橫切關注點,例如記錄執行時間、強制使用者驗證、快取結果(記憶)和審核 API 端點。
在底層,裝飾器是一個高階函數,它接受另一個函數作為參數,定義一個注入一些自訂邏輯的巢狀包裝函數,並傳回該包裝函數。 Python 提供了一種乾淨的速記語法,使用「@」符號將裝飾器應用於函數,使它們在視覺上優雅。
在編寫裝飾器時,您通常希望裝飾函數支援任意數量的位置參數和關鍵字參數。您可以透過設計巢狀包裝函數來接受“*args”和“**kwargs”並將它們傳遞給目標函數來實現這一點。此外,您應該在包裝函數上使用 functools.wraps 來保留原始函數的文件字串和名稱元資料。
程式碼和執行輸出
此腳本演示了編寫日誌裝飾器並包裝函數來檢查輸入、輸出和元資料。
decorators_tutorial.py
在編輯器中嘗試from functools import wraps
# 1. Defining a decorator
def log_execution(func):
@wraps(func) # Preserves original function metadata
def wrapper(*args, **kwargs):
print(f"[Log] Calling function: {func.__name__} with args: {args}")
result = func(*args, **kwargs)
print(f"[Log] Finished {func.__name__}. Result: {result}")
return result
return wrapper
# 2. Applying the decorator using @ syntax
@log_execution
def add_numbers(a, b):
"""Adds two numbers and returns the sum."""
return a + b
# 3. Invoking the decorated function
sum_result = add_numbers(15, 25)
print("Sum Result:", sum_result)
# Verifying metadata preservation
print("Docstring preserved:", add_numbers.__doc__)端子輸出
[Log] Calling function: add_numbers with args: (15, 25)
[Log] Finished add_numbers. Result: 40
Sum Result: 40
Docstring preserved: Adds two numbers and returns the sum.逐步實施
- 定義一個外部裝飾器函數,它將目標函數作為參數。
- 在巢狀包裝函數上匯入並套用 @functools.wraps(func) 以保護原始元資料。
- 實作wrapper(*args, **kwargs) 來捕獲輸入變數、注入邏輯並呼叫目標函數。
- 從裝飾器頭塊傳回包裝函數物件。
- 直接在目標函數簽章上方使用 @decorator_name 應用裝飾器。
常見問題解答
為什麼裝飾器內部需要@functools.wraps?
如果沒有包裝,裝飾函數就會失去其原始身分(其 __name__ 和 __doc__ 屬性被巢狀包裝函數的屬性取代),這使得偵錯和程式碼自省變得困難。
我可以將多個裝飾器應用於單一函數嗎?
是的!您可以透過堆疊放置多個 @ 行來連結裝飾器。 Python 從下往上應用它們(最接近函數定義的首先執行)。
相關主題
推薦的 Python 資源
透過相關的互動式教學、備忘單和程式碼比較來擴展您的知識。