Pythonでは、デコレータは関数やクラスをラップすることで、その機能を拡張するための設計パターンです。元の関数やクラスのコードを変更することなく、新たな機能を追加できます。以下は、Pythonのデコレータパターンを用いた基本的な例です。
import time
# 単純なログ出力デコレータを定義
def logging_decorator(func):
def inner_function(*args, **kwargs):
print(f"関数 '{func.__name__}' を呼び出します。")
result = func(*args, **kwargs)
print(f"関数 '{func.__name__}' が '{result}' を返しました。")
return result
return inner_function
# 元の関数
def calculate_sum(x, y):
return x + y
# デコレータを使って関数をラップ
calculate_sum = logging_decorator(calculate_sum)
# デコレートされた関数を呼び出す
print(calculate_sum(10, 20))
この例では:
logging_decoratorはデコレータ関数で、引数として関数(ここではcalculate_sum関数)を受け取ります。- デコレータの内部で、
inner_functionという新しい関数が定義されています。この関数には、元の関数の前後に実行したい追加のロジック(ログ情報の表示など)が含まれています。 inner_functionは、渡された元の関数func(*args, **kwargs)を呼び出し、その戻り値を処理します。- 最終的に、デコレータは
inner_functionオブジェクトを返します。 calculate_sum = logging_decorator(calculate_sum)の行で、実際に関数がデコレートされています。つまり、元の関数への参照が、デコレートされた新しい関数に置き換えられます。
また、デコレータは@記号を使ってより簡潔に適用できます。
# @記号を使ってデコレータを適用
@logging_decorator
def calculate_sum(x, y):
return x + y
# デコレータを手動で呼び出す必要はなく、デコレートされた関数を直接呼び出せます
print(calculate_sum(10, 20))
次に、デコレータを使って新しいスレッドで関数を実行し、非同期で動作させるものを作成します。以下はその簡単な例です。
import threading
# 非同期実行のためのデコレータ
def run_in_thread_decorator(func):
def executor(*args, **kwargs):
# 新しいスレッドを作成し、実行する関数とその引数を渡す
thread = threading.Thread(target=func, args=args, kwargs=kwargs)
# スレッドを開始
thread.start()
return executor
# 元の関数
def process_data(task_name, duration):
print(f"タスク '{task_name}' を開始します。")
time.sleep(duration) # 時間のかかる処理をシミュレート
print(f"タスク '{task_name}' が完了しました。")
# デコレータを使って関数をラップ
process_data_async = run_in_thread_decorator(process_data)
# デコレートされた関数を呼び出す
process_data_async("データ処理1", 3)
process_data_async("データ処理2", 2)
print("メインスレッドは引き続き実行を続けます...")
この例では:
run_in_thread_decoratorはデコレータ関数で、引数として関数(ここではprocess_data関数)を受け取ります。- デコレータの内部で定義された
executor関数は、新しいスレッドを作成し、元の関数とその引数をスレッドのtargetパラメータに渡してから、スレッドを開始します。 process_data関数をデコレータでラップした後、その関数を呼び出すと、実際には元の関数が新しいスレッドで実行されます。メインプログラムはすぐに戻り、後続のコードの実行を続けます。