キタコレ

デコレータがわからず悶々としていたが、またまたmorchin氏のコメントに助けられた。
2008-03-08 - rindai87の日記

特に難しい処理はしていません。deco(foo2)で、deco関数をfoo2を引数として呼び出しています。
関数decoは、print ”Hello, world!”を実行して、Noneを返します。
foo2 = deco(foo2)つまり、foo2 = Noneとなります。fooも同様です。

??
何のこっちゃと思っていたら、やっぱりそんなに難しいことではなかった。
サンプルコードがよろしくなかったのだろう。

def deco(func):
    print "I'm deco()"
    map(func, [1,2,3])

@deco
def foo(x):
    print x

def decolation(ls):
    print "I'm decolation()"
    def _show(x):
        print x
    return map(_show, ls)

def main():
    @deco
    def foo2(x):
        print x

    print "I'm here!"

    decolation([1,2,3])

    print foo
    print foo2

    foo(1)
    foo(2)

if __name__ == "__main__":
    main()

結果

D:\workspace\Python\3-10>python test.py
I'm deco()
1
2
3
I'm deco()
1
2
3
I'm here!
I'm decolation()
1
2
3
None
None
Traceback (most recent call last):
  File "test.py", line 31, in <module>
    main()
  File "test.py", line 27, in main
    foo(1)
TypeError: 'NoneType' object is not callable

なるほど!
関数のネストみたいになってるね。
そして

@decoと書いてfoo関数の定義が終了した時点でdeco関数が呼び出されていることに注意する必要があります。
逆に言えば、関数定義をしただけで関数が自動実行されるような仕組みがあるとも言えます。

確かに、

@deco
def foo(x):
    print x

とした時点でdeco()が呼び出されている。

さらに、やってることは

foo=deco(foo)

なので、fooはdeco()の返り値を受け取っている。
だから、デコレートした瞬間から、foo()は関数ではない、と。
これはかなり面白いよね!!
クロージャとかを組み合わせると、かなり不思議な挙動を示しそうだ。