如何在 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 資源

透過相關的互動式教學、備忘單和程式碼比較來擴展您的知識。