はじめに
このセクションでは、デコレータの概念について説明します。これは、私たちが表面をこすりぬけるだけの高度なトピックです。
ログ記録の例
関数を考えてみましょう。
def add(x, y):
return x + y
次に、それにいくつかのログ記録を追加した関数を考えてみましょう。
def add(x, y):
print('Calling add')
return x + y
次に、同様にいくつかのログ記録を持つ 2 番目の関数です。
def sub(x, y):
print('Calling sub')
return x - y
考察
考察:少々繰り返しています。
コードの重複が多いプログラムを書くことは、しばしば本当に面倒くさいものです。書くのが面倒くさく、保守も難しいです。特に、その動作方法を変更したい場合(たとえば、別の種類のログ記録にするかもしれません)はそうです。
ログ記録を行うコード
おそらく、ログ記録が追加された関数を生成する関数を作成できます。ラッパー関数です。
def logged(func):
def wrapper(*args, **kwargs):
print('Calling', func.__name__)
return func(*args, **kwargs)
return wrapper
次に、それを使用します。
def add(x, y):
return x + y
logged_add = logged(add)
logged から返される関数を呼び出すと何が起こりますか?
logged_add(3, 4) ## ログメッセージが表示されます
この例は、いわゆる ラッパー関数 を作成するプロセスを示しています。
ラッパーは、もう少しの処理を追加して別の関数をラップする関数ですが、それ以外は元の関数とまったく同じ方法で機能します。
>>> logged_add(3, 4)
Calling add ## 追加出力。ラッパーによって追加されました
7
>>>
注:logged() 関数はラッパーを作成し、それを結果として返します。
デコレータ
関数の周りにラッパーを配置することは、Python で非常に一般的です。非常に一般的なので、それに対する特別な構文があります。
def add(x, y):
return x + y
add = logged(add)
## 特別な構文
@logged
def add(x, y):
return x + y
この特別な構文は、上記に示したのとまったく同じ手順を実行します。デコレータはただの新しい構文です。それは関数を 装飾する と言われます。
解説
デコレータには、ここで提示したものよりもはるかに微妙な詳細があります。たとえば、クラスでの使用や、関数に複数のデコレータを使用する場合などです。ただし、前の例は、それらの使用方法がどのように生じるかをよく示しています。通常、広範な関数定義にわたって繰り返しコードが現れた場合に対応するためです。デコレータは、そのコードを中央の定義に移動させることができます。
演習 7.10:実行時間を計測するデコレータ
関数を定義すると、その名前とモジュールが __name__ と __module__ 属性に格納されます。たとえば:
>>> def add(x,y):
return x+y
>>> add.__name__
'add'
>>> add.__module__
'__main__'
>>>
timethis.py というファイルに、関数の実行にどれくらいの時間がかかるかを表示する追加のロジックで関数をラップするデコレータ関数 timethis(func) を書きます。これを行うには、次のような計測呼び出しで関数を囲みます:
start = time.time()
r = func(*args,**kwargs)
end = time.time()
print('%s.%s: %f' % (func.__module__, func.__name__, end-start))
ここに、あなたのデコレータがどのように機能するかの例を示します:
>>> from timethis import timethis
>>> @timethis
def countdown(n):
while n > 0:
n -= 1
>>> countdown(10000000)
__main__.countdown : 0.076562
>>>
考察:この @timethis デコレータは、どんな関数定義の前にも配置できます。したがって、パフォーマンスチューニングの診断ツールとして使用できます。
まとめ
おめでとうございます!あなたは関数デコレータの実験を完了しました。あなたのスキルを向上させるために、LabEx でさらに実験を行って練習してください。