69

これは Python 2.5 であり、GAEでもありますが、問題ではありません。

次のコードがあります。dec_checkクラスをデコレーターとして使用して、bar で foo() メソッドを装飾しています。

class dec_check(object):

  def __init__(self, f):
    self.func = f

  def __call__(self):
    print 'In dec_check.__init__()'
    self.func()

class bar(object):

  @dec_check
  def foo(self):
    print 'In bar.foo()'

b = bar()
b.foo()

これを実行するとき、私は見たいと思っていました:

In dec_check.__init__()
In bar.foo()

しかし、私はオブジェクトメソッドであるため、引数としてTypeError: foo() takes exactly 1 argument (0 given)取るようになっています。問題は、デコレータ コードを実行しているときに のインスタンスが実際には存在しないことだと思います。.foo()selfbar

barでは、のインスタンスをデコレータ クラスに渡すにはどうすればよいでしょうか。

4

3 に答える 3

94

デコレーターを記述子にする必要があります-その(メタ)クラスに__get__メソッドがあることを確認するか、より簡単に、デコレータークラスの代わりにデコレーター関数を使用します(関数はすでに記述子であるため)。例えば:

def dec_check(f):
  def deco(self):
    print 'In deco'
    f(self)
  return deco

class bar(object):
  @dec_check
  def foo(self):
    print 'in bar.foo'

b = bar()
b.foo()

これは印刷します

In deco
in bar.foo

望んだ通りに。

于 2010-03-02T18:47:35.367 に答える
53

関数が十分な場合、アレックスの答えで十分です。ただし、クラスが必要な場合は、次のメソッドをデコレータ クラスに追加することで機能させることができます。

def __get__(self, obj, objtype):
    """Support instance methods."""
    import functools
    return functools.partial(self.__call__, obj)

これを理解するには、記述子プロトコルを理解する必要があります。記述子プロトコルは、モノをインスタンスにバインドするためのメカニズムです。__get____set__およびで構成__delete__され、インスタンス ディクショナリからモノが取得、設定、または削除されたときに呼び出されます。

この場合、モノがインスタンスから取得されると、その__call__メソッドの最初の引数をインスタンスにバインドし、partial を使用します。これは、クラスが構築されるときにメンバー関数に対して自動的に行われますが、このような合成メンバー関数に対しては明示的に行う必要があります。

于 2010-07-21T04:28:13.913 に答える
6

デコレータをクラスとして書きたい場合は、次のようにします。

from functools import update_wrapper, partial

class MyDecorator(object):
    def __init__(self, func):
        update_wrapper(self, func)
        self.func = func

    def __get__(self, obj, objtype):
        """Support instance methods."""
        return partial(self.__call__, obj)

    def __call__(self, obj, *args, **kwargs):
        print('Logic here')
        return self.func(obj, *args, **kwargs)

my_decorator = MyDecorator

class MyClass(object):
     @my_decorator
     def my_method(self):
         pass
于 2017-07-27T21:57:04.100 に答える