上級プログラマーのための Python デコレータ ガイド
Python デコレータは、関数やメソッドの動作を変更するための強力で柔軟なツールです。プログラマーは、これらを使用して、呼び出し可能なオブジェクトの機能を、わかりやすく、読みやすく、保守しやすい方法で拡張または変更できます。この記事では、ネストされたデコレータ、デコレータ引数、クラスベースのデコレータなど、Python デコレータに関連する高度な概念について説明します。
デコレータとは何ですか?
デコレータは、別の関数の動作を変更する関数です。デコレータは別の関数をラップして、明示的にコードを変更せずにその動作を拡張します。デコレータは、@decorator_name
構文を使用して定義され、関数定義の上に配置されます。
基本的なデコレータ構文
シンプルなデコレータは、関数を引数として受け取り、何らかの動作を追加する内部関数を定義し、その内部関数を返します。
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
引数付きデコレータ関数
デコレータは、引数を受け入れることでより柔軟になります。このようなデコレータを作成するには、デコレータを返す関数を記述する必要があります。これにより、デコレータにさらに動的な動作を追加できます。
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
func(*args, **kwargs)
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
ネストデコレータ
デコレータはネストして複数の動作を組み合わせることができます。たとえば、1 つの関数に 2 つ以上のデコレータを使用できます。
def uppercase_decorator(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
def repeat_decorator(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result + result
return wrapper
@repeat_decorator
@uppercase_decorator
def say_word(word):
return word
print(say_word("hello"))
クラスベースのデコレータ
Python では、__call__
メソッドを使用して、デコレータをクラスとして実装することもできます。クラスベースのデコレータは、より複雑な状態管理と動作が必要な場合に便利です。
class CountCalls:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"Call {self.num_calls} of {self.func.__name__!r}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")
say_hello()
say_hello()
functools.wraps
を使用してメタデータを保存する
デコレータを記述すると、デコレータされた関数は、名前やドキュメント文字列などの元のメタデータを失います。 functools.wraps
デコレータを使用すると、元の関数のメタデータをラッパー関数にコピーできます。
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Wrapper function executed before", func.__name__)
return func(*args, **kwargs)
return wrapper
@my_decorator
def display_info(name, age):
"""Displays name and age."""
print(f"display_info ran with arguments ({name}, {age})")
print(display_info.__name__) # Output: display_info
print(display_info.__doc__) # Output: Displays name and age.
結論
Python デコレータは、柔軟なコード設計と動作の変更を可能にする強力な機能です。ネストされたデコレータ、引数付きのデコレータ、クラスベースのデコレータなどの高度な使用法により、Python プログラムにさらに多くの機能と読みやすさを提供できます。デコレータを正しく理解して使用することで、開発者はより簡潔で効率的で読みやすいコードを作成できます。