デコレーター
Pythonのデコレータ(Decorator)は、関数やクラスの機能を簡単に修正または拡張する機能です。通常、関数を扱う高度な機能を実装する際に使用され、関数やメソッドの実行前後にコードを追加したり、関数の返り値を変更したり、例外を処理したりすることができます。
デコレータは、関数で実装され、他の関数を引数として受け取り、内部でそれを変更したり新しい関数を返したりします。通常、@decorator_function
のような形で、関数やメソッドの直前に使用されます。
例として、関数の実行時間を計測するデコレータを示します:
import time
def measure_time(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Execution time: {end_time - start_time} seconds")
return result
return wrapper
@measure_time
def some_function():
time.sleep(1)
print("Function executed")
some_function()
上記の例では、measure_time
デコレータがsome_function
関数を包み込み、実行時間を計測してその値を出力します。@measure_time
を使ってデコレータを適用し、some_function()
を呼び出すと、関数の実行前後の時間が出力されます。
デコレータはログ記録、認証および権限の確認、キャッシュ、バリデーションなど、さまざまなタスクに有効に使用できます。複数のデコレータを組み合わせて使用したり、クラスのメソッドにも適用することができます。Pythonのデコレータは、コードをよりきれいで再利用可能にする強力なツールです。
クラスデコレーター
クラスにデコレータを適用する方法について説明します。
Pythonでは、クラスのメソッドにもデコレータを適用することができます。通常の関数の場合と同様に、デコレータは関数として実装され、@decorator_function
のようにメソッドの上に使用されます。
例として、メソッドの実行時間を計測するデコレータをクラスに適用する方法を示します:
import time
def measure_time(method):
def wrapper(self, *args, **kwargs):
start_time = time.time()
result = method(self, *args, **kwargs)
end_time = time.time()
print(f"{self.__class__.__name__}.{method.__name__} の実行時間: {end_time - start_time} 秒")
return result
return wrapper
class MyClass:
@measure_time
def some_method(self):
time.sleep(1)
print("メソッドが実行されました")
obj = MyClass()
obj.some_method()
上記の例では、measure_time
デコレータがMyClass
クラスのsome_method
メソッドを包み込み、その実行時間を計測して表示します。@measure_time
でデコレータを適用すると、メソッドを呼び出すたびにその実行時間が表示されます。
クラスにデコレータを適用する際の注意点としては、デコレータ関数の第一引数はself
である必要があります。これにより、デコレータがメソッドが属するインスタンスを正しく認識できます。
クラスデコレータは、ログ記録、認証、キャッシュなどの追加機能を実装する際に非常に有用です。これにより、コードの再利用性と可読性を向上させることができます。
よく使うデコレーター
Pythonでよく使用されるデコレータの1つに、@property
デコレータがあります。このデコレータは、クラスのメソッドをプロパティとしてアクセスできるようにする機能を提供します。通常、オブジェクト指向プログラミングではクラスの属性にアクセスするためにメソッドを介してアクセスすることが多いですが、@property
デコレータを使用すると、これを簡単に実現することができます。
例として、次のようなクラスを考えてみましょう:
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value <= 0:
raise ValueError("半径は正数でなければなりません。")
self._radius = value
@property
def area(self):
return 3.14 * self._radius * self._radius
# Circleクラスの使用例
circle = Circle(5)
print(f"半径: {circle.radius}")
print(f"面積: {circle.area}")
circle.radius = 10
print(f"変更された半径: {circle.radius}")
print(f"変更された面積: {circle.area}")
上記の例では、@property
デコレータを使用してradius
メソッドをプロパティとしてアクセスできるようにしました。これにより、circle.radius
のように属性のように使用でき、同時に@radius.setter
を使用してこの属性に値を設定する際にバリデーションを追加することができます。
@property
デコレータは、クラスのメソッドを属性のようにアクセス可能にし、属性の設定時に追加のロジックを挿入することができるため、非常に便利です。