読者です 読者をやめる 読者になる 読者になる

デコレータを書く時にはfunctools.wrapsを使おう

Python

リビアルな例だが、元の関数(func)をデコレート・ラップするmydecoratorというデコレータを書いた時、下のように単純にinnerを返すと、

def mydecorator(func):
    def inner(*args, **kwds):
        print "Hi, I'm inner!"
        return func(*args, **kwds)
    return inner

@mydecorator
def hello(to):
    """
    Say hello to somebody
    """
    print "Hello, %s!" % to

if __name__ == '__main__':
    print repr(hello)
    print hello.__doc__

結果として、

<function inner at 0xb7e6edf4>
None

のように、デコレートされた元の関数(hello)の関数名やドキュメント文字列が失われてしまう。

デコレータを書くたびに「もっときちんと書かないとなー」と思いつつも手を抜いていたが、Python2.5以降ならばfunctools.wrapsを使えばよいということを知った。

上のコードをfunctools.wrapsで書き直せば次の通り。

from functools import wraps

def mydecorator(func):
    def inner(*args, **kwds):
        print "Hi, I'm inner!"
        return func(*args, **kwds)
    return wraps(func)(inner)

@mydecorator
def hello(to):
    """Say hello to somebody"""
    print "Hello, %s!" % to

if __name__ == '__main__':
    print repr(hello)
    print hello.__doc__

元の関数名もドキュメント文字列も失われない。

<function hello at 0xb7eb60d4>
Say hello to somebody