Decoratorのまとめ

Pythonには素敵なdecoratorという機能がある.これは関数やメソッドを修飾し,関数実行に対してある意味メタな挙動を与えることができる.ちょっとわかりにくいのは,decoratorは関数を返す関数として定義するという点だろう.さらに引数をとるdecoratorになると関数を返す関数を返す関数として定義しなければならない.

before

関数実行に入る前に何かを出力するようなdecoratorを書いてみる.

def before(_func):
    def _f(*arg, **kw):
        print 'before'
        _func(*arg, **kw)
    return _f

関数_fをローカルに定義して,その関数を返している.使うときには,次のように使う.

@before
def target():
    print 'target'

これは,次と等しい,のだそうだ.

def target():
    print 'target'
target = before(target)

つまり,target自身をdecorator関数に与えて呼び出して得られた関数で,targetを再定義するのである.あたらしくできたtargetを呼び出すと,decorator関数beforeの中で定義された_fが呼び出される.そのなかでbeforeと書き出した後に,_func を呼び出しているが,これには旧targetがバインドされている.したがって,結果的にはbeforeのあとにtargetが書き出されることになる.

引数つきのbefore

beforeで書き出される文字を引数で制御することを考える.こんな感じ.

@before('target')
def target():
    print 'target'

この場合には,decorator関数を返す関数としてbeforeを書かなければならない.

def before(param):
    def _deco(_func):
        def _f(*arg, **kw):
            print 'before', param
            _func(*arg, **kw)
        return _f
    return _deco 

ややこしや...上述のように使った場合,宣言の時点で一番外側のbeforeと_decoが実行され,得られた関数_fが実行時に実行される.