デコレータ
Pythonにはデコレータ構文がある。
関数を他の関数で包んで、機能を追加するのが(使う分には)簡単にできる構文だ。
TurboGearsでは、テンプレートの指定や入力チェック、認証チェックなどをデコレータで行うようになっている。
詳しい説明は以下の資料で。
http://www.nasuinfo.or.jp/FreeSpace/kenji/sf/python/virtualMachine/decorator.htm
デコレータを実際に作る方法も上記資料で詳しく述べられているが、Python2.5から使えるfunctools.partialを使った方法を検討してみた。
まず、クロージャだけで実現させる例。
二重にクロージャ書くのがだるい。っていうか分かりにくい
関数をうけとって関数を返す関数を返す?
def trace(before, after): def decorate(func): def trace_func(*args, **kwargs): before() result = func(*args, **kwargs) after() return result return trace_func return decorate def before(): print "before" def after(): print "after" @trace(before, after) def hello(): print "hello"
呼び出し可能オブジェクトを使った例。
引数を受け付けるのがコンストラクタに移るので、クロージャが一段減る。
class Trace(object): def __init__(self, before, after): self.before = before self.after = after def __call__(self, func): def trace(*args, **kwargs): self.before() result = func(*args, **kwargs) self.after() return result return trace def before(): print "before" def after(): print "after" @Trace(before, after) def hello(): print "hello"
パーシャル関数を使った例
引数設定をパーシャルで固定して、ラップする関数を引数とした関数にする。
デコレータの書き方が上のやつと変わってしまうのが難点。
from functools import partial def trace(before, after, func): def trace(*args, **kwargs): before() result = func(*args, **kwargs) after() return result return trace def before(): print "before" def after(): print "after" @partial(trace, before, after) def hello(): print "hello"
もう少し検討すれば、paritalの恩恵を受けつつ通常と同じ書き方ができそうな気がするのだが。