Life is Really Short, Have Your Life!!

ござ先輩の主に技術的なメモ

Pythonのデコレータ学習メモ

関数を引数に新しい関数を返すだけの話を言語機構としてデコレータという概念で表現しているらしい。コード見たほうが速いので、デコレータのPythonコードを書く。

#関数を引数に取って、
def deco_outer(some_func):
    def inner():
        print "before_some_func"
        #取った引数である関数を実行し
        ret = some_func()
        #なんか化粧して
        return ret + 1
    #化粧した関数を返す
    return inner

#化粧対象となる関数を用意
def bar():
    return 1

#化粧した関数を作って
hoge = deco_outer(bar)
#実行だああ
print hoge()
#before_some_func
#2

これだけ見ると、クロージャで自分の好きな関数を作って返しているだけの話なので、別にこれといって感あるよね・・・。func apply (func,a,b) { return func(a,b) } みたいな話を言われてもなんやねんみたいな。

で、デコレータっていうのはこの関数を作る部分を簡便に書くことが出来ることを言うらしい。

def bar():
    return 1

hoge = deco_outer(bar)
print hoge()

#これを簡便化するとこうなる
@deco_outer
def bar():
    return 1
#barはdeco_outerの内部で使われる関数であると明示的に指定できる
print bar()

使い道としては必ずこの関数を実行する時の前処理・後処理の実行を行なう時かな。フレームワークを作る時に絶対使われると思う。Bottleだとrouteというデコレータが使われている。

DBアクセスを例に取れば、deco_outerの中でコネクション取得してAutoCommitを設定して文字コードはどうこう・・・みたいな情報を与えて、barの中では実際に行ないたいDBアクセスやビジネスロジックを実行して、その結果を返せばいい。実行後はdeco_outerの中でコネクションをCloseする処理を書けば安全に使える。

少し違うけど、Javaだとデコレータパターンというデザインパターンがある。JavaのIOパッケージで使われている機能拡張手法がそれに近いっちゃ近い。

//こんなやつね。
BufferedReader br = new BufferedReader(new FileReader("member.csv"));

インターフェイスをimplしたクラスのインスタンス変数に、拡張対象となるインスタンスを持たせるという。こうすればnewでラップすればするほど拡張が可能になるし、継承関係が必要ないから柔軟に出来るというメリットが有る。

12. Decorator パターン | TECHSCORE(テックスコア)

うーん、面白いですね。