デコレータ自身がパラメータを受け取りたい場合、関数をもう一段ネストさせます。「デコレータを返す関数」を作るイメージです。
基本構造
引数を取るデコレータは 3 層構造になります。
def repeat(n): def decorator(func): def wrapper(*args, **kwargs): for _ in range(n): result = func(*args, **kwargs) return result return wrapper return decorator
使い方は以下のとおりです。
@repeat(3) def say_hello(): print("Hello!") say_hello()
実行すると「Hello!」が 3 回出力されます。@repeat(3) は repeat(3) を呼び出してデコレータを取得し、それを関数に適用しています。つまり say_hello = repeat(3)(say_hello) と同じ意味です。
実用例:リトライ処理
失敗時に再試行するデコレータを作ってみましょう。
import time def retry(max_attempts, delay=1): def decorator(func): def wrapper(*args, **kwargs): for attempt in range(max_attempts): try: return func(*args, **kwargs) except Exception as e: if attempt < max_attempts - 1: print(f"リトライ {attempt + 1}/{max_attempts}: {e}") time.sleep(delay) else: raise return wrapper return decorator @retry(max_attempts=3, delay=2) def fetch_data(): # ネットワーク処理など pass
このように引数付きデコレータを使うと、デコレータの挙動を柔軟にカスタマイズできます。