ブログトップ 記事一覧 ログイン 無料ブログ開設

神様なんて信じない僕らのために このページをアンテナに追加 RSSフィード

2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
基本的に適当な日記です。あまり鵜呑みにしないでください。土日はWeb離れしているので反応遅れます。

2010-12-09

[]PythonのWebフレームワーク使うなら知っておきたいデコレータ

最近「オワタ\(^o^)/」で有名なDjangoしか触ってないダメ人間です。

こんにちは。

Djangoとかどうでもいいがな、

Webフレームワークとかめんどくさいがな、

という最近なのでDつながりでDecoratorの話をします。

ナウでヤングなPythonistaのホットな話題はGCの参照カウンタ

ではなくてFlaskとかかもしれないですが、

@app.route("/")
def hello():
    return "Hello World!"

こいつも多分に漏れずDecoratorを使います。

Djangoでも、

@require_GET

とか

@require_POST

とか使ったり見たことがあるんじゃないかと思います。

で、意外と魔法っぽいデコレータですが、

これっていったいどうなってんの?

って事を知らない人が割といたりします。

「とりあえず指定しろって言われたから指定してますサーセンwww」

という感じ何じゃないでしょうか。


なので、よく使われがち&便利でかつ

「デコレータにした方が良いケースなのにロジック記述になってる」なんてことも多々ありますので、

ヤングなPythonistaに「んなこと知ってんだよ」と言われながらも

デコレータについて書いてみようと思います。


Pythonのデコレータってそもそもシンタックスシュガーなんですが、

簡単に言うと、

・デコレータで指定した関数を受け取り、その関数そのものないしはその関数を呼び出す関数を返す

という用途で使われます。


【関数そのものを返す】場合はデコレータ引数とその関数を何らかに関連づけたい、とかで使いますし、

【関数を呼び出す関数を返す】場合はフック関数として使われることが殆どかと思います。


で、Webフレームワークだとこんな感じ。

オールドタイプなのでDjangoスタイルで。


http://codepad.org/3HHjAY6q

# -*- coding: utf-8 -*-

# デコレータ
def require_foo(foo_type):

    def decorator(func):
        # func はこの場合 bar (関数オブジェクト)
        # bar の前にフックする関数をラップしてそれを返すことができる
        def inner(request, *args, **kwargs):
            # このデコレータに修飾された関数はこのinnerにラップされる
            request += foo_type # 適当だが
            return func(request, *args, **kwargs)
        return inner
    return decorator

@require_foo('hoge')
def bar(request):
    # Django のviewと思ってね
    return request

if __name__ == '__main__':
    request = 'Hallo World.'
    print bar(request) # bar は innerである

    print bar
    print bar.func_name

デコレータが引数を必要とするので

def require_foo(foo_type):

が一番外にありますが、引数がいらない場合はこれはいらないです。

http://codepad.org/cRsvoqrt

ここで問題として、

print bar

とすると

<function inner at 0x4034c844>

とかになります。

print bar.func_name

inner

です。(ラップ関数の方をbarに代入しているので当たり前ですが)


これだと困るという場合には、

from functools import wraps

を使ってください。

http://codepad.org/HVjuRZMS

@wraps(func)

をinnerにつけるだけで関数名を正してくれます。


普段適当にデコレータを使うと可読性も下がりますが、

Webフレームワークの場合にはデコレータ自作することも多々ありますし、

@require_POST
@require_GET
def hoge(request):
    pass

みたいに重ねることもあるでしょうから、

何が起きているのか憶えておくとお得です!(デコレータチェインの動作とか、一応ね)


Webフレームワークの話じゃねえええ、という文句は次の人に言ってください。


次はとらドラ好きで有名な渋川さんがいいのかなあとか。

(スルーされたので@takanoryで? 未確定)


参考文献。