2

引数を取る基本デコレーターがありますが、それは他のデコレーターによっても構築されています。装飾された関数の完全な署名を保持するために、 functools.wraps をどこに配置すればよいかわかりません。

import inspect
from functools import wraps

# Base decorator
def _process_arguments(func, *indices):
    """ Apply the pre-processing function to each selected parameter """
    @wraps(func)
    def wrap(f):
        @wraps(f)
        def wrapped_f(*args):
            params = inspect.getargspec(f)[0]

            args_out = list()
            for ind, arg in enumerate(args):
                if ind in indices:
                    args_out.append(func(arg))
                else:
                    args_out.append(arg)

            return f(*args_out)
        return wrapped_f
    return wrap


# Function that will be used to process each parameter
def double(x):
    return x * 2

# Decorator called by end user
def double_selected(*args):
    return _process_arguments(double, *args)

# End-user's function
@double_selected(2, 0)
def say_hello(a1, a2, a3):
    """ doc string for say_hello """
    print('{} {} {}'.format(a1, a2, a3))

say_hello('say', 'hello', 'arguments')

このコードの結果は次のようになります

saysay hello argumentsarguments

ただし、say_hello で help を実行すると、次のようになります。

say_hello(*args, **kwargs)
    doc string for say_hello

パラメータ名以外はすべて保持されます。

別の @wraps() をどこかに追加する必要があるようですが、どこですか?

4

2 に答える 2

0

direprobs は、functools ラップの量が私をそこに連れて行かないという点で正しかったです。bravosierra99 は、多少関連する例を示してくれました。ただし、外側のデコレータが引数を取るネストされたデコレータで署名を保存する例は 1 つも見つかりませんでした。

Bruce Eckel の引数付きデコレーターに関する投稿へのコメントは、私が望む結果を達成するための最大のヒントを与えてくれました。

重要なのは、_process_arguments 関数内から中間関数を削除し、そのパラメーターを次のネストされた関数に配置することでした。今ではちょっと理にかなっています...しかし、うまくいきます:

import inspect
from decorator import decorator

# Base decorator
def _process_arguments(func, *indices):
    """ Apply the pre-processing function to each selected parameter """
    @decorator
    def wrapped_f(f, *args):
        params = inspect.getargspec(f)[0]

        args_out = list()
        for ind, arg in enumerate(args):
            if ind in indices:
                args_out.append(func(arg))
            else:
                args_out.append(arg)

        return f(*args_out)
    return wrapped_f


# Function that will be used to process each parameter
def double(x):
    return x * 2

# Decorator called by end user
def double_selected(*args):
    return _process_arguments(double, *args)

# End-user's function
@double_selected(2, 0)
def say_hello(a1, a2,a3):
    """ doc string for say_hello """
    print('{} {} {}'.format(a1, a2, a3))

say_hello('say', 'hello', 'arguments')
print(help(say_hello))

そして結果:

saysay hello argumentsarguments
Help on function say_hello in module __main__:

say_hello(a1, a2, a3)
    doc string for say_hello
于 2016-08-31T21:59:02.623 に答える