Python のクラスベースデコレータ
デコレータは関数だけでなく、クラスとしても実装できます。状態を保持したい場合や、複雑なロジックを整理したい場合に有効です。
基本構造
クラスベースのデコレータは __init__ で関数を受け取り、__call__ でラッパー処理を行います。
from functools import wraps
class CountCalls:
def __init__(self, func):
wraps(func)(self)
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"{self.func.__name__} は {self.count} 回呼ばれました")
return self.func(*args, **kwargs)
使い方は関数デコレータと同じです。
@CountCalls
def say_hello():
print("Hello!")
say_hello() # say_hello は 1 回呼ばれました / Hello!
say_hello() # say_hello は 2 回呼ばれました / Hello!
クラスなので、self.count のように状態を自然に保持できます。
引数を取るクラスデコレータ
引数を取る場合は、__init__ で引数を受け取り、__call__ で関数を受け取ります。
class Repeat:
def __init__(self, n):
self.n = n
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(self.n):
result = func(*args, **kwargs)
return result
return wrapper
@Repeat(3)
def greet():
print("Hi!")
@Repeat(3) でインスタンスが生成され、その __call__ にデコレート対象の関数が渡されます。関数ベースの 3 層ネストよりも構造が明確になることがあります。