更新:2024/10/17
Pythonのデコレーターの使い方・例題について


ふゅか
デコレーターって、関数に処理を追加できるすごく便利な機能なんだよね♪

はるか
関数の実行時間を計測したいときとかに使えそう。
目次
1. デコレーターとは
デコレーターは、関数やメソッドに機能を追加するための仕組みです。デコレーターは、関数の性質を利用して、ある関数の前後に処理を追加したり、関数を改良したりするのに便利な方法です。
2. 基本的な使い方
デコレーターは、関数を引数に取り、別の関数を返す関数です。
2.1. 基本的なデコレーターの例
まずは、シンプルなデコレーターの例を見てみましょう。
def my_decorator(func):
def wrapper():
print("関数が呼び出される前に実行されます")
func() # 引数の関数を実行
print("関数が呼び出された後に実行されます")
return wrapper
my_decorator
は、元の関数 func
を受け取り、その前後に処理を追加している wrapper
関数を返しています。これを元の関数に適用してみます。
@my_decorator
def say_hello():
print("こんにちは!")
say_hello()
2.1.1. 実行結果
関数が呼び出される前に実行されます
こんにちは!
関数が呼び出された後に実行されます
@my_decorator
の部分が、デコレーターの適用です。これは say_hello
関数を my_decorator
に渡し、wrapper
関数に置き換えることを意味しています。
2.1.2. デコレーターの仕組み
デコレーターがどう動いているのかを順番に説明します。
- 元の関数 (
say_hello
) がmy_decorator
に渡されます。 my_decorator
は、wrapper
関数を返します。@my_decorator
によって、wrapper
関数が実行されます。wrapper
関数が実行されると、元のsay_hello
関数の前後にメッセージが表示され、さらにsay_hello
関数自体も実行されます。

はるか
基本的な使い方はわかった。関数を引数に取って、内部で定義した関数を返すだけか。

ふゅか
そうそう!「関数が呼び出される前に実行されます」と「後に実行されます」って、デコレーターで一つの関数に色々な処理を追加できちゃうんだ~。
2.2. 引数を持つ関数にデコレーターを使う
引数を持つ関数にデコレーターを適用する場合、wrapper
関数にも引数を受け取れるようにする必要があります。
def my_decorator(func):
def wrapper(name): # 任意の引数を受け取る
print("関数が呼び出される前に実行されます")
result = func(name) # 引数を渡して関数を実行
print("関数が呼び出された後に実行されます")
return result
return wrapper
@my_decorator
def say_hello(name):
print(f"こんにちは、{name}!")
say_hello("ふゅか")
2.2.1. 実行結果
関数が呼び出される前に実行されます
こんにちは、ふゅか!
関数が呼び出された後に実行されます
2.3. 可変長引数を使う
先ほど、wrapper関数にnameの変数を渡していましたが、任意の引数(可変長引数)にしてもプログラムは動きます。
def my_decorator(func):
def wrapper(*args, **kwargs): # 任意の引数を受け取る
print("関数が呼び出される前に実行されます")
result = func(*args, **kwargs) # 引数を渡して関数を実行
print("関数が呼び出された後に実行されます")
return result
return wrapper
@my_decorator
def say_hello(name):
print(f"こんにちは、{name}!")
say_hello("ふゅか")

ふゅか
引数を持つ関数にデコレーターを適用する場合も簡単だよ![*args, **kwargs] で任意の引数を受け取れるようにするだけ♪

はるか
引数が渡されても、デコレーターの構造自体は変わらない。
2.4. 例:関数の実行時間を測るデコレーター
次に、デコレーターの例として、関数の実行時間を測定するデコレーターを作ってみます。
import time
def time_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time() # 開始時間を記録
result = func(*args, **kwargs)
end_time = time.time() # 終了時間を記録
print(f"関数 {func.__name__} の実行時間: {end_time - start_time} 秒")
return result
return wrapper
@time_decorator
def slow_function():
time.sleep(2) # 2秒待機
print("関数が実行されました")
slow_function()
実行結果は次のようになります。
このデコレーターは、関数の前後で時間を記録し、実行時間を表示しています。
3. デコレーターの例題
3.1. 例題1: 砂の量を増やすデコレーター
砂漠での一日で、砂の量が2倍に増えることをシミュレートするデコレーターを作成します。
砂の量
を表す関数にデコレーターを適用して、2倍に増える計算を行いなさい。期待される出力:
200
解答の手順:
sand_double
というデコレーターを定義し、引数として与えられた量を2倍にする処理を記述します。sand_in_desert
関数にデコレーターを適用し、砂の量を2倍にする機能を付与します。- 初期の砂の量(100)を与えた際に、デコレーターがそれを2倍にして出力します。
解答:
def sand_double(func):
def wrapper(amount):
return func(amount) * 2
return wrapper
@sand_double
def sand_in_desert(amount):
return amount
print(sand_in_desert(100))
3.2. 例題2: 砂の耐久テストデコレーター
砂の山に何度も人が歩くことを想定し、デコレーターで砂の山の耐久度を試します。もし砂の山の耐久度が0以下になった場合、崩壊するメッセージを出力します。
解答の手順:
sand_durability
というデコレーターを作成し、耐久度が歩数で減少するロジックを組みます。durability - steps
が0以下になると、崩壊のメッセージを返す処理を追加します。walk_on_sand
関数で耐久度を管理し、デコレーターを適用して、耐久度を減らす機能を持たせます。
解答:
def sand_durability(func):
def wrapper(durability, steps):
if durability - steps <= 0:
return "砂の山は崩壊しました!"
return func(durability, steps)
return wrapper
@sand_durability
def walk_on_sand(durability, steps):
return f"残りの砂の耐久度: {durability - steps}"
print(walk_on_sand(10, 5))
print(walk_on_sand(10, 15))
3.3. 例題3: 砂時計デコレーター
砂時計の時間を計測するため、デコレーターを使って関数が完了するまでにかかる時間を測定します。すべての砂が落ちるのに2秒かかるとします。
期待される出力:
処理時間: 2.0秒
砂が落ちました
解答の手順:
sand_timer
デコレーターを作成し、開始時間と終了時間を測定する処理を追加します。sand_fall
関数は砂が落ちる処理(2秒間の待機)を再現します。- デコレーターを適用して、処理時間を出力します。
解答:
import time
def sand_timer(func):
def wrapper():
start_time = time.time()
result = func()
end_time = time.time()
return f"処理時間: {end_time - start_time}秒\\\\n{result}"
return wrapper
@sand_timer
def sand_fall():
time.sleep(2) # 砂が落ちるのに2秒かかる
return "砂が落ちました"
print(sand_fall())
check
Pythonの基本から応用まで、幅広くカバーする記事を公開中です。学習のポイントや実践的なコード例を通じて、Pythonの魅力と実用性を深く理解することができます。ぜひ、こちらの記事で気になる記事を見つけてください!
PR