私が Python でプログラミングを始めたとき、確かバージョンは 3.3 でした。したがって、私がプログラミングを始めたとき、デコレーターは長い間 Python コミュニティで利用可能でした。
関数デコレータはバージョン 2.2 で Python に導入され、クラス デコレータはバージョン 2.6 で Python に導入されました。
個人的には、Python の Decorator 機能はこの言語の非常に強力な機能であると考えています。
実際、私の目標は、Python で最も理解しにくいトピックについて一連の記事を作成することです。 10 個以上あるこれらのトピックを 1 つずつ取り上げる予定です。
この記事では、デコレータのトピックのあらゆる部分についてできる限り触れていきます。
本質的に、デコレータは Python の設計パターンであり、これを使用すると、コア構造を変更せずに関数またはクラスの動作を変更できます。デコレーターはメタプログラミングの一種であり、基本的に他のコードを操作するコードを作成します。
Python は、以下の順序で指定されたスコープを使用して名前を解決することをご存知でしょう:
デコレータは、クロージャの概念と密接に関連するエンクロージング スコープに座っています。
重要なアイデア: デコレーターは関数を入力として受け取り、それに機能を追加し、変更された関数を返します。
例え: デコレーターをギフトの包装紙と考えてください。ギフト (本来の機能) があり、それを装飾紙 (デコレーター) で包み、見た目を良くしたり、追加の機能 (リボンやカードなど) を追加したりします。中身のギフトは変わりませんが、そのプレゼンテーションや関連するアクションが強化されています。
Python のほとんどのデコレータは関数を使用して実装されますが、クラスを使用してデコレータを作成することもできます。
関数ベースのデコレータはより一般的でシンプルですが、クラスベースのデコレータはさらなる柔軟性を提供します。
def my_decorator(func): def wrapper(*args, **kwargs): # Do something before calling the decorated function print("Before function call") result = func(*args, **kwargs) # Do something after calling the decorated function print("After function call") return result return wrapper @my_decorator def say_hello(name): print(f"Hello, {name}!") say_hello("World")
説明:
これらは、関数の代わりにクラスを使用してデコレーターを定義します。
class MyDecorator: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): # Do something before calling the decorated function print("Before function call") result = self.func(*args, **kwargs) # Do something after calling the decorated function print("After function call") return result @MyDecorator def say_hello(name): print(f"Hello, {name}!") say_hello("World")
説明:
デコレーターの基本概念は、別の関数を引数として受け取り、明示的に変更することなくその動作を拡張する関数であるということです。
最も単純な形式は次のとおりです:
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 # Using the decorator with @ syntax @my_decorator def say_hello(): print("Hello!") # When we call say_hello() say_hello() # This is equivalent to: # say_hello = my_decorator(say_hello)
関数の実行時間を記録するデコレータを作成しましょう:
def decorator_with_args(func): def wrapper(*args, **kwargs): # Accept any number of arguments print(f"Arguments received: {args}, {kwargs}") return func(*args, **kwargs) # Pass arguments to the original function return wrapper @decorator_with_args def greet(name, greeting="Hello"): print(f"{greeting}, {name}!") greet("Alice", greeting="Hi") # Prints arguments then "Hi, Alice!"
これらは独自のパラメータを受け入れることができるデコレータです:
def repeat(times): def decorator(func): def wrapper(*args, **kwargs): for _ in range(times): result = func(*args, **kwargs) return result return wrapper return decorator @repeat(times=3) def greet(name): print(f"Hello {name}") return "Done" greet("Bob") # Prints "Hello Bob" three times
def singleton(cls): instances = {} def get_instance(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return get_instance @singleton class DatabaseConnection: def __init__(self): print("Initializing database connection") # Creating multiple instances actually returns the same instance db1 = DatabaseConnection() # Prints initialization db2 = DatabaseConnection() # No initialization printed print(db1 is db2) # True
これらは、クラス メソッド用に特別に設計されています:
def debug_method(func): def wrapper(self, *args, **kwargs): print(f"Calling method {func.__name__} of {self.__class__.__name__}") return func(self, *args, **kwargs) return wrapper class MyClass: @debug_method def my_method(self, x, y): return x + y obj = MyClass() print(obj.my_method(5, 3))
複数のデコレータを 1 つの関数に適用できます:
def bold(func): def wrapper(): return "<b>" + func() + "</b>" return wrapper def italic(func): def wrapper(): return "<i>" + func() + "</i>" return wrapper @bold @italic def greet(): return "Hello!" print(greet()) # Outputs: <b><i>Hello!</i></b>
説明:
functools.wraps デコレータ (ドキュメントを参照) は、デコレータでラップしたときに元の関数のメタデータ (名前、docstring、シグネチャなど) を保持するヘルパー関数です。使用しないと、この重要な情報が失われます。
例:
def my_decorator(func): def wrapper(*args, **kwargs): """Wrapper docstring""" return func(*args, **kwargs) return wrapper @my_decorator def my_function(): """My function docstring""" pass print(my_function.__name__) print(my_function.__doc__)
出力:
wrapper Wrapper docstring
問題:
解決策: functools.wraps を使用します):
def my_decorator(func): def wrapper(*args, **kwargs): # Do something before calling the decorated function print("Before function call") result = func(*args, **kwargs) # Do something after calling the decorated function print("After function call") return result return wrapper @my_decorator def say_hello(name): print(f"Hello, {name}!") say_hello("World")
出力:
class MyDecorator: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): # Do something before calling the decorated function print("Before function call") result = self.func(*args, **kwargs) # Do something after calling the decorated function print("After function call") return result @MyDecorator def say_hello(name): print(f"Hello, {name}!") say_hello("World")
デコレータは関数呼び出し間の状態を維持することもできます。これは、関数呼び出しのキャッシュやカウントなどのシナリオで特に役立ちます。
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 # Using the decorator with @ syntax @my_decorator def say_hello(): print("Hello!") # When we call say_hello() say_hello() # This is equivalent to: # say_hello = my_decorator(say_hello)
出力:
def decorator_with_args(func): def wrapper(*args, **kwargs): # Accept any number of arguments print(f"Arguments received: {args}, {kwargs}") return func(*args, **kwargs) # Pass arguments to the original function return wrapper @decorator_with_args def greet(name, greeting="Hello"): print(f"{greeting}, {name}!") greet("Alice", greeting="Hi") # Prints arguments then "Hi, Alice!"
説明:
ラッパー関数は、装飾された関数が呼び出されるたびに増加するカウンター (呼び出し) を維持します。
これは、デコレータを使用して状態を維持する方法の簡単な例です。
Python デコレータの厳選されたリストは以下で見つけることができます:
デコレーターは、Python の強力かつエレガントな機能であり、関数やクラスをクリーンで宣言的な方法で強化できます。
原則、ベスト プラクティス、潜在的な落とし穴を理解することで、デコレータを効果的に活用して、よりモジュール化され、保守しやすく、表現力豊かなコードを作成できます。
これらは、Python プログラマーにとって貴重なツールであり、特にフレームワークを使用したり、再利用可能なコンポーネントを構築したりする場合に役立ちます。
以上がPython デコレータ: 包括的なガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。