デコレータ

デコレータは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に置き換わったと考えれば分かりやすい。

まぁ普通はこんな難しいことはしないと思うけど。