7

パラメータを持つこのデコレータが機能しないのはなぜですか?

def decAny( f0 ):
    def wrapper( s0 ):
        return "<%s> %s </%s>" % ( any, f0(), any )
    return wrapper

@decAny( 'xxx' )
def test2():
    return 'test1XML'

print( test2() )

「strは呼び出し可能ではありません」というエラーが常に表示されます。これは、処理する代わりにwrapper()内で戻り文字列を実行しようとしており、結果文字列を返します

4

3 に答える 3

16

デコレータは、関数を返す関数です。「デコレーターにパラメーターを渡す」場合、実際に行っているのは、デコレーターを返す関数を呼び出すことです。したがってdecAny()、関数を返す関数を返す関数であるべきです。

次のようになります。

import functools

def decAny(tag):
    def dec(f0):
        @functools.wraps(f0)
        def wrapper(*args, **kwargs):
            return "<%s> %s </%s>" % (tag, f0(*args, **kwargs), tag)
        return wrapper
    return dec

@decAny( 'xxx' )
def test2():
    return 'test1XML'

例:

>>> print(test2())
<xxx> test1XML </xxx>

*args発生していた特定の問題を修正することに加えて、ラップされた関数にとを引数として追加し、それらをデコレータ内の呼び出しに**kwargs渡すことで、コードを少し改善したことに注意してください。f0これにより、任意の数の位置引数または名前付き引数を受け入れる関数をデコレートでき、引き続き正しく機能します。

ここについて読むことができますfunctools.wraps()
http://docs.python.org/2/library/functools.html#functools.wraps

于 2013-03-25T21:11:53.737 に答える
1

「Mark Lutz - Learning Python」本からの良いサンプルがあります:

def timer(label=''):
    def decorator(func):
        def onCall(*args):   # Multilevel state retention:
            ...              # args passed to function
            func(*args)      # func retained in enclosing scope
            print(label, ... # label retained in enclosing scope
        return onCall
    return decorator         # Returns the actual decorator

@timer('==>')                # Like listcomp = timer('==>')(listcomp)
def listcomp(N): ...         # listcomp is rebound to new onCall

listcomp(...)                # Really calls onCall
于 2014-03-21T15:42:25.097 に答える