デコレータの引数
デコレータは引数を取ることができると Python 2.4 の What's new に書いてあった。
http://www.python.org/doc/2.4/whatsnew/node6.html
Decorator functions can take arguments. If arguments are supplied, your decorator function is called with only those arguments and must return a new decorator function; this function must take a single function and return a function, as previously described. In other words, @A @B @C(args) becomes:
def f(): ... _deco = C(args) f = A(B(_deco(f)))Getting this right can be slightly brain-bending, but it's not too difficult.
適当訳:
デコレータ関数は引数を取ることができる。もし引数が与えられると、あなたのデコレータ関数はそれらの引数とともに呼ばれ、そして新しいデコレータ関数を return しなければならない。前述の通り、この関数(どれ?)は1つの関数とり、1つの関数を返さなければならない。つまり、@A @B @C(args)*1はこうなる。
def f(): ... _deco = C(args) f = A(B(_deco(f)))正しくこれを理解するのに頭をひねる*2かもしれないが、そんなに難しくない。
こんな変な機能何に使うんだ? と思ったら Python 2.5 から標準ライブラリ入りした functools で使われていた。
http://www.python.org/doc/2.5/whatsnew/pep-309.html
適当訳:wraps() is a decorator that can be used inside your own decorators to copy the wrapped function's information. An alternate version of the previous example would be:
def my_decorator(f): @functools.wraps(f) def wrapper(*args, **kwds): print 'Calling decorated function' return f(*args, **kwds)
なるほど。確かに引数を取れるようにするのは意味がある。wraps()は、独自のデコレータの中で、ラップされる関数の情報をコピーするためのデコレータである。前の例は代わりにこう書ける。
def my_decorator(f): @functools.wraps(f) def wrapper(*args, **kwds): print 'Calling decorated function' return f(*args, **kwds)