0

参考文献

この質問を書く前に、私は次の興味深い質問のいくつかを参照しましたが、このシナリオは説明/カバーされていないと感じています。

私はfunction次のようにしています:

def simple_function():
    print 'this is a simple_function'

そして、私はclassいくつかで以下を持っていますmethods

class Test:

    def Test_method_1(self, func, args=None, kwargs=None):
        print 'this is Test::Test_method_1'
        <execute some instructions here>

    def Test_method_2(self):
        print 'this is Test::Test_method_2'

私は次のように使用Test_method_1simple_functionています:

t = Test()
t.Test_method_1(simple_function)

simple_functionが任意の引数を取る場合、は次のTest_method_1ように呼び出されます。

def simple_function(a, b, c, d=f, g=h):
    print 'this is a simple_function'

t = Test()
t.Test_method_1(simple_function, args=[a, b, c], kwargs={d:f, g:h})

Test_method_2さて、のとして使いたいdecorator versionですTest_method_1。したがって、simple_function定義は次のように書くことができます。

t = Test()

@t.Test_method_2
def simple_function():
    print 'this is a simple_function'

注:は適切な引数を使用してTest_method_2呼び出します。Test_method_1

今の質問:

  • 1-これは可能ですか?
  • 2-可能であれば、装飾された関数の名前(ここ)は(を含む)simple_functionへの引数としてどのように渡されますか?Test_method_2self
  • 3- [ここにキラーの質問があると思います] Test_method_2(デコレータ)と simple_function(デコレーションされる関数)の両方に任意の引数を渡したい--引数(を含む)を受け取るためにを*args and **kwargsどのTest_method_2ように定義する必要がありますselfか?

Test_method_2両方の任意の引数を持つのデコレータとしての使用法はsimple_function次のとおりです。

t = Test()
@t.Test_method_2(a, b, c, d, e=f, g=h)
def simple_function(x, y, z, n=m):
    print 'this is a simple_function'
4

1 に答える 1

1

確かにそれは可能です。構文が行うのは、@decorator後続の関数を定義してからデコレータを呼び出し、後続の関数を渡して、その関数への参照を返されたものに置き換えることだけです。

したがって、次のようになります。

@foo
def bar():
    pass

に翻訳されます:

def bar():
    pass
bar = foo(bar)

つまり、t.Test_method_2()メソッドは1つの引数、つまり装飾される関数を予期し、呼び出し可能なものを返す必要があります。

import functools

def Test_method_2(self, func):
    @functools.wraps(func)
    def wrapper(self, *args, **kw):
        print 'Wrapped function name:', func.__name__
        return func(*args, **kw)
    return wrapper

ラッパー関数を返し、呼び出されたときにラップされた関数の名前を出力する最小限のデコレータになります。引数が何と呼ばれるかは関係ありません; ここで使用funcしましたが、任意の正当なPython識別子にすることができます。

これselfは、メソッドシグネチャの標準部分です。Test_method_2インスタンスを参照しているためt、Pythonはselfすべてのメソッドと同様に、パラメーターを自動的に処理します。

それ以降@は単なる表現です。したがって、構文を使用する場合:

@t.Test_method_2(a, b, c, d, e=f, g=h)

次に、Test_method_2()代わりにデコレータ関数を返す必要があります。スコープのネストの1つの追加レベルは、次のことを行う必要があります。

def Test_method_2(self, *args, **kw):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*wrapperargs, **wrapperkw):
            fargs = args + wrapperargs
            fkw = dict(kw)
            fkw.update(wrapperkw)
            return func(*fargs, **fkw)
        return wrapper
    return decorator

これを分解する:

@t.Test_method_2(5, 6, 7, 8, baz='spam', ham='eggs')
def simple_function(x, y, z, n=m):
    print 'this is a simple_function'

の後の部分は、入れ子関数@を返します。t.Test_method_2(5, 6, 7, 8, baz='spam', ham='eggs')decorator

@decorator
def simple_function(x, y, z, n=m):
    print 'this is a simple_function'

次に、どのpythonが次のようになりますか。

simple_function = decorator(simple_function)

decorator(func)返しますwrapper(*wrapperargs, **wrapperkw)

simple_function(1, 2, foo='bar')次に呼び出すとwrapper(1, 2, foo='bar') の引数が呼び出され、位置引数とキーワード引数として渡されます。simple_function()fargs = [5, 6, 7, 8, 1, 2]fkw = {'baz': 'spam', 'ham': 'eggs', 'foo': 'bar'}

リンクされた質問に表示されるクラスデコレータパターンも同様に機能します。後の式@は、呼び出されたものを返します。ネストされた関数の代わりに、クラスインスタンスが代わりに作成されます。これは、デコレータが使用する状態を格納するための2つの異なるアプローチです。

ネストされた関数は、記述が少しコンパクトですが、クラスを使用すると、ネストされたスコープよりも多くのイントロスペクションオプションが提供されます。

于 2013-02-10T21:24:04.530 に答える