Python 函數裝飾器 (Function Decorator) 筆記

✅ 什麼是函數裝飾器?

  • 函數裝飾器(Function Decorator)是一種用來修改或擴展函數功能的設計模式。它允許在不改變函數本身的情況下,將額外的邏輯附加到函數上。

  • 函數裝飾器是高階函數 Higher-order Function:接收一個函數作為參數,並返回一個包裹在該函數的新函數 (Wrapper)。

函數裝飾器是 Python 中一種強大的功能,允許我們修改或擴展現有函數的行為,而無需改變函數的代碼。它是一種語法糖,基於高階函數的概念,使得函數變得更加靈活和可重複使用。

函數裝飾器的結構

def decorator(func):
    def wrapper(*args, **kwargs):
        # 在此處進行一些處理或擴展功能
        return func(*args, **kwargs)
    return wrapper
  • decorator(func):裝飾器函數,接收被裝飾的函數 func
  • wrapper(*args, **kwargs):內部包裝函數,可以修改或擴展 func 的行為。
  • return wrapper:返回包裝函數 wrapper,這樣我們就能在裝飾器中處理邏輯。

💡 為何要使用裝飾器?

  1. 功能擴展:可以在不修改函數內容的情況下,擴展或修改其行為。
  2. 程式碼重用:可以將重複的邏輯提取出來,放在裝飾器中,減少重複代碼。
  3. 增強函數功能:通過裝飾器可以給函數增加額外的功能,像是日誌、權限檢查、緩存等。

📝 基本範例

def simple_decorator(func):
    def wrapper():
        print("Before function call.")
        func()
        print("After function call.")
    return wrapper

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

say_hello()

輸出:

Before function call.
Hello!
After function call.

如何運作:

  1. @simple_decorator 是裝飾器的語法糖,等同於 say_hello = simple_decorator(say_hello)
  2. 裝飾器會包裝 say_hello 函數,使它在被調用時執行額外的邏輯。

🔄 帶參數的裝飾器

如果需要裝飾器接受參數,可以再定義一層函數。這樣可以讓裝飾器變得更加通用。

帶參數範例

def calculator(func):
    def calculate_height(weight, height):
        def square_height(height):
            height_in_meters = height / 100
            return height_in_meters
        return func(weight, square_height(height))
    return calculate_height

@calculator
def bmi_calculator(weight, height):
    return weight / (height * height)

result = bmi_calculator(50, 160)
print(result)  # 19.531249999999996

解釋:

  1. calculator 是裝飾器,接受 bmi_calculator 作為參數。
  2. calculate_height 函數內部,我們調用 square_height 函數來將身高轉換為米,然後再計算 BMI。

帶參數裝飾器的工作原理:

  1. @calculator 會讓 bmi_calculatorcalculator 包裝。
  2. 裝飾器內的 calculate_height 會在 bmi_calculator 函數之前執行,進行額外處理。

🔑 函數裝飾器的好處:

  • 可以動態地修改函數的行為。
  • 使得原始函數更簡潔,擴展的邏輯集中於裝飾器內部,提升代碼可維護性。
  • 允許代碼更加模組化和解耦。

📚 常見應用場景:

  1. 日誌記錄:記錄函數的調用及參數。

    範例:

    def log_decorator(func):
        def wrapper(*args, **kwargs):
            print(f"Calling {func.__name__} with arguments: {args}, {kwargs}")
            return func(*args, **kwargs)
        return wrapper
    
    @log_decorator
    def add(a, b):
        return a + b
    
    add(3, 4)  # 輸出: Calling add with arguments: (3, 4), {}
    
  2. 計時器:計算函數執行所花的時間。

    範例:

    import time
    
    def timer_decorator(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            end_time = time.time()
            print(f"Execution time: {end_time - start_time} seconds")
            return result
        return wrapper
    
    @timer_decorator
    def slow_function():
        time.sleep(2)
    
    slow_function()  # 輸出: Execution time: 2.0xxxxxx seconds
    
  3. 權限檢查:在函數執行之前檢查用戶權限。

    範例:

    def permission_check(func):
        def wrapper(user_role, *args, **kwargs):
            if user_role != "admin":
                raise PermissionError("You do not have permission to access this function.")
            return func(user_role, *args, **kwargs)
        return wrapper
    
    @permission_check
    def delete_user(user_role, user_id):
        print(f"User {user_id} deleted.")
    
    delete_user("admin", 123)  # 正常執行
    delete_user("guest", 123)   # 會拋出 PermissionError
    
  4. 緩存:為函數結果加上緩存,避免重複計算。

    範例:

    def cache_decorator(func):
        cache = {}
        def wrapper(*args, **kwargs):
            if args in cache:
                print("Returning cached result")
                return cache[args]
            result = func(*args, **kwargs)
            cache[args] = result
            return result
        return wrapper
    
    @cache_decorator
    def expensive_computation(x):
        print("Performing expensive computation...")
        return x * x
    
    expensive_computation(10)  # 輸出: Performing expensive computation...
    expensive_computation(10)  # 輸出: Returning cached result
    

這樣的範例可以幫助更好地理解每個應用場景,並將裝飾器的應用擴展到真實開發中。

對於新手來說,理解 function decorator 可以從以下幾個步驟入手:

  1. 理解函數是物件:首先,理解 Python 函數是物件,可以作為參數傳遞給其他函數。

  2. 學會基本裝飾器範例:如日誌記錄、計時等。先從簡單的範例開始,逐步理解其運作。

  3. 從簡單的實例開始:不要一開始就嘗試複雜的場景。實踐簡單的範例來熟悉裝飾器的結構。

  4. 了解如何使用 @ 語法@decorator 是 Python 中簡化使用裝飾器的語法,它背後實際上是將函數傳遞給裝飾器。

學會裝飾器後,可以根據需求進行進一步的學習和應用。

面試時如何回答 function decorator

1. 簡單解釋

裝飾器是一種用來修改或擴展函數功能的設計模式。它允許在不改變函數本身的情況下,將額外的邏輯附加到函數上。

2. 常見應用場景

  • 日誌記錄
  • 計時
  • 權限檢查
  • 緩存

3. 基本結構

  • 裝飾器是高階函數:接收一個函數作為參數,並返回一個包裹該函數的新函數。

4. 示範範例

def decorator(func):
    def wrapper():
        print("Before function execution")
        func()
        print("After function execution")
    return wrapper

@decorator
def greet():
    print("Hello!")

5. 考試重點

  • 知道裝飾器的語法 @decorator
  • 解釋如何將邏輯封裝到函數外部
  • 理解裝飾器的用途與運作原理