Python で引数を取るデコレータの作り方
デコレータ自身がパラメータを受け取りたい場合、関数をもう一段ネストさせます。「デコレータを返す関数」を作るイメージです。
基本構造
引数を取るデコレータは 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
このように引数付きデコレータを使うと、デコレータの挙動を柔軟にカスタマイズできます。