デコレータ
デコレータはPython2.4から導入。
class X: @classmethod def foo(): pass
この@から始まるのがデコレータで、上の例だとfooメソッドをクラスメソッドにしている。Java1.5のアノテーションによく似ているが、だからといってこういう特殊な用途のための構文というわけではなく、
@a @b def foo(): pass
などと書いた場合は単に
def foo(): pass foo = a(b(foo)) # fooは呼び出されていないことに注意
のように実行される。つまりメソッドオブジェクトや関数オブジェクトを指定した関数に自動で通してくれる機能というわけ。上の例のように下から順に(1行で書いたなら右から順に)適用される。aもbも普通の関数だけど、引数として渡されるオブジェクトを必ずreturnしなきゃいけない。まぁ目的によっては別のものを返してもいいけど、それだと何がしたいんだか分からない。
じゃあJavaのアノテーションみたいな使い方はできないのかというと、それは工夫次第でなんとかなる。Javaでいう@deprecatedにしたいならそういう名前の関数をデコレータにして警告を出力すればいいし、@overrideみたいなのでオーバーライドしているかしていないかチェックしてもいい。関数オブジェクトに属性を追加したりしてもいい。
リフレクションに頼らなくていい分使いこなしやすい。
あとデコレータに引数を渡すこともできなくはない。その場合引数を渡されたデコレータは実際には関数オブジェクトが渡されることもなくその場で実行されてしまって、それ自体はデコレータにならない。でもそのデコレータのつもりだった関数が別のデコレータを返してやればデコレータとして機能する。
def b(func): print func return func def a(str): print str return b @a('abc') def foo(): pass
上の例だとa('abc')が呼ばれ、その返り値であるbが通常のデコレータのように呼ばれる。@a('abc')のa('abc')の部分がbに置き換わったと考えれば分かりやすい。
まぁ普通はこんな難しいことはしないと思うけど。