Page cover

Class Decorators


Decorators 是強大的工具,允許我們修改函數或 Class 的行為。 Decorators 可以某種方式修改 Class。這通常涉及返回一個新 Class,該新 Class 用一些修改或增強的功能替換原始 Class。

PYTHON
def add_attribute(cls):
    cls.new_attribute = "New attribute added by decorator"
    return cls

@add_attribute
class MyClass():
    pass

# Areate an instance of MyClass
obj = MyClass()

# Access the new attribute
print(obj.new_attribute)  # Output: New attribute added by decorator

下面是一範例,它將任何調用的方法的結果乘以 10。 在這種情況下,double_results decorator 會檢查 Class 的所有方法,如果找到任一個可調用方法,它將用 double_decorator 函數包裝它,使結果值加倍。

PYTHON
def double_results(cls):
    # iterate over all attributes
    for attr_name, attr_value in cls.__dict__.items():
        if callable(attr_value):  # if the attribute is a method
            setattr(cls, attr_name, double_decorator(attr_value))
    return cls

def double_decorator(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs) * 10
    return wrapper

@double_results
class MyClass:
    def add(self, a, b):
        return a + b

# create an instance of MyClass
obj = MyClass()

# call the 'add' method
print(obj.add(2, 2))  # Output: 40

Class decorators 是一個更高層次的概念,不僅需要了解 Classes 如何工作,還需要了解 decorators 如何工作。

Decorators允許輕鬆修改類和函數,而無需更改其原始碼。 這遵循物件導向編程中的 Open–closed principle 。(物件應該對擴展開放,但對修改應該關閉)

Decorator Class


Python 中的 decorator 是用於修改函數、方法或 Class 的任何可調用物件。 可調用物件是任何可以被調用的物件 (具有 __call__ 方法的函數或 Class)。

使用 Class 實現的 decorator 可以提供更多的靈活性和對裝飾應用方式的控制。

簡單的 decorator 來追蹤函數被調用的次數:

PYTHON
class CallCount:
    def __init__(self, f):
        self.f = f
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"This function is called {self.count} times")
        return self.f(*args, **kwargs)

@CallCount
def hello(name):
    print(f"Hello, {name}")

執行結果:

This function is called 1 times
Hello, Python

Decorator class 用於計時函數執行:

PYTHON
import time

class Timer:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        start_time = time.time()
        result = self.func(*args, **kwargs)
        end_time = time.time()
        print(f"Executing {self.func.__name__} took {end_time - start_time:4f} s")
        return result

@Timer
def complex_calculation(n):
    return sum(i*i for i in range(n))

print(complex_calculation(10000))

執行結果:

Executing complex_calculation took 0.001001 s
333283335000

範例 – 帶參數的 Decorator Class


要創建帶有參數的 Class-based decorator,我們需要確保 Class 本身接受這些參數。

PYTHON
class Repeat:
    def __init__(self, num_times):
        self.num_times = num_times

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            for _ in range(self.num_times):
                result = func(*args, **kwargs)
            return result
        return wrapper

@Repeat(num_times=3)
def greet(name):
    print(f"Hello {name}")

greet("Alice")

執行結果:

Hello Alice
Hello Alice
Hello Alice

範例 – Decorator Class 實例


PYTHON
class DecoratorClass:
    def __init__(self, value):
        self.value = value

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print(f"Before function call, value is: {self.value}")
            result = func(*args, **kwargs)
            print(f"After function call, value is: {self.value}")
            return result
        return wrapper

    def increment(self):
        self.value += 1

decorator = DecoratorClass(10)
decorator.increment()

@decorator
def test_function():
    print("Inside the function")

test_function()

執行結果:

Hello Alice
Hello Alice
Hello Alice

PEP 614


PEP 代表 Python Enhancement Proposal (增強提案),它是一個描述 Python 新功能和改進的標準。 這些 PEP 在被接受並在 Python 中實現之前,經過了仔細的審查和討論過程。

PEP 614 (Python 3.9 ver.) 消除了 decorators 語法的限制,允許任何有效的表達式充當裝飾器;允許更具表現力和更複雜的裝飾器。

參考資料


decorator — Python 3.11.4 documentation

PEP 318 – Decorators for Functions and Methods | peps.python.org

PEP 3129 – 類裝飾器 | peps.python.org

PEP 614 – 放寬對裝飾器的語法限制 | peps.python.org

PEP 698 – 覆蓋靜態類型裝飾器 | peps.python.org

Python進階技巧 (3) — 神奇又美好的 Decorator ,嗷嗚! | by Jack Cheng | 整個程式都是我的咖啡館 | Medium

[Python教學] 裝飾詞原理到應用 | Max行銷誌

Python Decorator 入門教學

Python 有哪些好玩的語法糖? - 知乎

Python語法糖系列_上帝De助手的博客-CSDN博客_語法糖

詳解Python修飾器(語法糖)_咆哮的阿傑的博客-CSDN博客_修飾器

Python 中甜甜的語法糖 - 騰訊雲開發者社區-騰訊雲

Python 中甜甜的語法糖_牛客博客

python中裝飾器&語法糖(syntax sugar)@_Mr_ggx的博客-CSDN博客_python怎樣達到和語法糖同樣的效果

Python 函數裝飾器 | 菜鳥教程

裝飾器 - 廖雪峰的官方網站

Python 中的裝飾器 - GeeksforGeeks

Python 中帶參數的裝飾器 - GeeksforGeeks

collections - 如何在 python 中使用 kwargs 作為裝飾器的參數_python_酷徒編程知識庫

Python 中帶參數的裝飾器 - GeeksforGeeks

DAY09-搞懂Python的裝飾器 - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天

collections - 如何在 python 中使用 kwargs 作為裝飾器的參數_python_酷徒編程知識庫

Python 中帶參數的裝飾器 - GeeksforGeeks

Last updated

Was this helpful?