Page cover

Decorator 【修飾器】


Python 中的 decorator 是一個修改另一個函數功能的函數。 Decorator 可以被視為使用另一個函數擴展其行為,而不顯式修改它的函數。 由 @ 語法表示,可以在函數或 Class 定義之前使用。

Decorators 實現了以下幾個目標:

  1. 程式碼可重用性和 Don't Repeat Yourself 原則: Decorators 允許您定義可重用的構建 blocks,這些構建 blocks 可以更改或擴展其他函數或方法的行為。 它們可以應用於任何需要附加功能的函數或方法,從而提高程式碼的可重用性並遵守 DRY (不要重複自己) 原則。

  2. 促進 Separation of concerns: 透過在 decorator 中封裝對函數行為的更改或新加,您可以使主函數的程式碼保持簡潔並更加專注於其主要任務。 這支援了 Separation of concerns (關注點分離) 的設計原則。

  3. 在不修改函數程式碼的情況下更改行為: 使用 decorators,您可以在不更改函數 source code 的情況下更改函數的行為。 當您想要向無法或不想更改的函數添加行為時,這會很有用。 例如:向 Python 標準 library 或第三方 library 中的函數,增加日誌記錄、計時功能、記憶性。

範例 – 基礎範例


my_decorator 是一個接受另一個函數作為參數的函數 (在本例中為 say_hello)。 my_decorator 中的 wrapper 函數是一個嵌套 (nested) 函數,它調用 say_hello (原始函數),但還在函數調用之前和之後加入了一些功能。

PYTHON
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

# =========================================================
# Replace the decorator

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_hello():
    print("Hello!")

decorated_say_hello = my_decorator(say_hello)
decorated_say_hello()

執行結果:

帶參數的 Decorators (Decorator factory)


Decorators 也可以接受參數 (arguments)。 以下是定義帶有參數的 decorator 的方法:

scale_and_shift 是一個 decorator factory:返回 decorator 的函數。 當您使用 @scale_and_shift(...) 語法時,您首先調用 scale_and_shift(...),它返回實際的decorator。

Decorator 是一個函數,它接受一個函數 func 作為參數,並返回一個 wraps (包裝) func 的新函數 wrapperwrapper 函數使用它收到的任何參數調用 func

Decorator 在 wrapper 函數中使用 *args**kwargs,允許 func 接受任意數量和類型的參數。

所有 decorators 只是一種接受一個參數並返回一個值,除了使用 decorator factory。

Decorators 應用順序


Python 中的裝飾器按照它們的編寫順序應用,即從最接近函數的位置開始向上。 為了更好地理解這一點,請考慮以下程式碼:

函數 greet() 的輸出被傳遞給 decorator2,然後 decorator2(greet) 的輸出被傳遞給 decorator1

執行結果:

Python 在函數定義時運行 decorators,而不是在函數調用時運行。 這使得裝飾器適合在定義函數時需要完成一次的任務,例如: 將函數註冊為事件的處理程序。

Syntactic sugar


Syntactic sugar (語法糖) 是一個在編程中使用的術語,用於描述編程語言中的語法,目的在使內容更易於閱讀或表達。 它的目的是讓語言更適合人類使用,也就是說,它使編碼更簡單或更易讀。

與許多語言一樣,Python 也有大量的 syntactic sugar。 這不會改變程式碼的作用; 它只是以不同的方式編寫相同的內容。例如:

Python 中的 decorators 也是一種 syntactic sugar 。函數前面的 @ 符號是 decorator。 它是 syntactic sugar,消除了將 decorator 作為函數本身調用的需要,並使程式碼更清晰。

雖然 syntactic sugar 可以使程式碼更易於閱讀和編寫,但有時也會使其變得更加複雜,特別是對於那些不熟悉所使用的習慣用法和語法的人來說。 因此,需要明智地使用這些工具,並確保可讀性和表達能力。

執行結果:

Last updated

Was this helpful?