gae アプリ 開発メモ

Google App Engine アプリの開発メモ / 言語: python, javascript / ビギナー

デコレータ

なんの気なしに @classmethod とか @staticmethod とか使っていたけど、なかなかの仕組みらしい。

デコレータとは

Pythonの用語集(decorator)より。

(デコレータ) 関数を返す関数。
通常、 @wrapper という文法によって関数を変換するのに利用されます。
デコレータの一般的な利用として、 classmethod() と staticmethod() があります。

デコレータ = ただの関数だという柔軟性にビックリ。
要は必要があれば、自分で定義できちゃうってことだ。

デコレータの制約は

  • 関数を引数とする
  • 関数を返す

というシンプルな制約のみ。

だから、デコレータには

  • __call__() を持つオブジェクト
  • __call__() を持つクラス

を指定することもできる。

追記
関数は返さなくてもよい。property()がそれ。

特に、クラスを指定した場合、

  1. 指定した関数はコンストラクタの引数にしてオブジェクトが生成される
  2. 指定した関数を呼び出すと、生成したオブジェクトの __call__() が呼び出される

といった振る舞いになる。

使い道

PythonDecoratorLibrary

  • State Machine Implementaion
  • Singleton
  • Synchronization

など実用的な使い道が公開されていた。

デコレータを実行するタイミング

@wrapper の表記で書いたデコレータが実行されるのは、@wrapper が読み込まれた時。
一般的には、関数の【実行時】ではなく、関数の【定義時】にデコレートする。
以下、サンプルコード。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def deco_fn(fn):
    print 'deco_fn'
    return fn

class deco_class(object):
    def __init__(self, fn):
        print 'deco_class.__init__()'
        self._fn = fn

    def __call__(self, *args):
        print 'deco_class.__call__()'
        self._fn(*args)

class A(object):
    @deco_fn
    def foo(self):
        print 'foo'

@deco_class
def boo():
    print 'boo'

def main():
    print '---'
    print 'execute start.'
    a = A()
    a.foo()
    boo()
    print 'execute end.'

if __name__ == '__main__':
    main()

で、結果。

deco_fn
deco_class.__init__()
---
execute start.
foo
deco_class.__call__()
boo
execute end.

もー、複雑すぎてワクワクする仕組みだ。