この連載では、Pythonについて色々な形で再学習に取り組んでいます。前回の記事はこちらになります。
前回は、デコレーターの意味について学びました。色々な引数のパターンに対応するために、デコレーター関数の中にラッパー関数を持たせます。

今回はデコレーターの使用例、応用例を見ていきます。
所用時間の確認
関数を開発しているときに、実行にかかる時間を測定したい場面があります。そんな時にデコレーターを使用すれば、関数本体に手を加えることなく所用時間を測ることができます。
import time def timer_deco(func): def wrap(*args, **kwargs): print(func.__name__) start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f"所要時間: {end_time - start_time} 秒") return result return wrap @timer_deco def test_func(): print("test_func処理開始") time.sleep(2) test_func() # test_func # test_func処理開始 # 所要時間: 2.000764846801758 秒
開発が完了したら、関数の前に記述しているデコレーターを削除すればいいのです。
作業ログ
関数が実行される際にログ(記録)を取りたい場合があります。関数が1つだけの場合は該当の関数に記述すればいいのですが、複数の関数に対して同様のログを取りたい場合は、関数毎にコードを書くのは非効率です。このような処理の場合、デコレーターの使用が有効です。
import datetime def log_deco(func): def wrap(*args, **kwargs): result = func(*args, **kwargs) print(datetime.datetime.now() , end = " : 関数 ") print(func.__name__ , end = ": 引数 ") print(*args, **kwargs, end = ": 返り値 : ") print(result) return return wrap @log_deco def func_1(): pass @log_deco def func_2(a,b): return a * b @log_deco def func_3(val_1,val_2 = 2): return val_1 * val_2 func_1() func_2(3, 4) func_3(3) # 2024-09-20 09:59:05.340213 : 関数 func_1: 引数 : 返り値 : None # 2024-09-20 09:59:05.340213 : 関数 func_2: 引数 3 4: 返り値 : 12 # 2024-09-20 09:59:05.340213 : 関数 func_3: 引数 3: 返り値 : 6
この例では標準出力に出力していますが、実際にはファイルに出力することになるでしょう。色々な引数のパターンに対応できています。
条件チェック
特定の条件を満たした対象のみ、関数の使用を許可したい場合があります。そんな関数が複数ある場合、デコレーターで条件チェック機能をまとめて実装すると効率的です。
def rank_check(func): def wrap(user): if user['rank'] in ["A","B"]: return func(user) else: print(f"{user['name']}さんは、使用できません") return wrap @rank_check def say_hello(user): print(f"{user['name']}さん、こんにちは") user_1 = {"name": "Alice", "rank": "A"} user_2 = {"name": "Tom", "rank": "B"} user_3 = {"name": "Bob", "rank": "C"} say_hello(user_1) say_hello(user_2) say_hello(user_3) # Aliceさん、こんにちは # Tomさん、こんにちは # Bobさんは、使用できません
この例ではランクがAかBのメンバーのみ、関数say_helloを使用できます。
クラスのインスタンスメソッドへの適用
クラスのインスタンスメソッドにも、デコレーターを使用できます。
def deco(func): def wrap(self): print(f"{func.__name__}が呼ばれました") return func(self) return wrap class MyClass: @deco def greet(self): print("こんにちは") obj = MyClass() obj.greet() # greetが呼ばれました # こんにちは
次回もデコレーター(エラー対応)
いかがでしょうか。デコレーターは色々な使い道が考えられますね。次回はデコレーターを使ったエラー対応について考えてみます。お楽しみに!!