デコレータは本質的には、コードを変更せずに他の関数が追加の関数を追加できるようにする Python 関数です。デコレータの戻り値も関数オブジェクトです。これは、ログ挿入、パフォーマンス テスト、トランザクション処理、キャッシュ、権限の検証など、横断的な要件を持つシナリオでよく使用されます。デコレータはこのような問題を解決する優れた設計であり、関数自体とは関係のない類似コードを大量に抽出して再利用し続けることができます。
一言で言えば、デコレーターの機能は、既存の関数またはオブジェクトに追加の機能を追加することです。
1. デコレータの書き方
初期の頃 (Python バージョン < 2.4、2004 年以前)、関数に機能を追加する場合は次のように記述されていました。
def debug(func):
def wrapper():
print "[DEBUG]: enter {}()".format(func.__name__)
return func()
return wrapper
def say_hello():
print "hello!"
say_hello = debug(say_hello) # 添加功能并保持原函数名不变
上記のデバッグ関数は実際にはデコレーターであり、元の関数をラップして別の関数を返し、いくつかの追加関数を追加します。この方法での記述はあまり洗練されていないため、Python の新しいバージョンでは @ 構文シュガーがサポートされており、次のコードは以前の記述方法と同等です。
def debug(func):
def wrapper():
print "[DEBUG]: enter {}()".format(func.__name__)
return func()
return wrapper
@debug
def say_hello():
print "hello!"
これは最も単純なデコレータですが、問題があり、デコレータ関数がパラメータを渡す必要がある場合、このデコレータは壊れます。wrapper
返された関数はパラメーターを受け入れることができないため、デコレータ関数が元の関数と同じパラメーターを受け入れるように指定できます。次に例を示します。
def debug(func):
def wrapper(something): # 指定一毛一样的参数
print "[DEBUG]: enter {}()".format(func.__name__)
return func(something)
return wrapper # 返回包装过函数
@debug
def say(something):
print "hello {}!".format(something)
このようにして、問題を 1 つ解決しますが、さらに N 個の問題が発生します。何千もの関数があるため、自分の関数だけを気にすることになります。他の人の関数パラメーターがどのようなものであるか誰が知っていますか? 幸いなことに、Python には変数パラメーター*args
とキーワード パラメーターが用意されて**kwargs
おり、これら 2 つのパラメーターを使用すると、デコレーターを任意のターゲット関数に使用できます。
def debug(func):
def wrapper(*args, **kwargs): # 指定宇宙无敌参数
print "[DEBUG]: enter {}()".format(func.__name__)
print 'Prepare and say...',
return func(*args, **kwargs)
return wrapper # 返回
@debug
def say(something):
print "hello {}!".format(something)
この時点で、デコレータの基本的な作成方法を完全にマスターしました。
2. 組み込みデコレータ
@classmethod は、クラス メソッドを定義するために使用される Python のデコレータです。クラス メソッドは、インスタンスではなくクラスに関連付けられているメソッドであり、最初にインスタンスを作成せずにクラス名によって直接呼び出すことができます。