32

重複の可能性:
クラスメソッドをデコレータにすることはできますか?

ここに例があります。

class myclass:
    def __init__(self):
        self.start = False

    def check(self):
        return not self.start

    def doA(self):
        if self.check():
            return
        print('A')

    def doB(self):
        if self.check():
            return
        print('B')

ご覧のとおり、デコレータ方式でチェックアクションを記述したいのですが、何度も試した結果、クラス外でしかメソッドを記述できないことがわかりました。クラス内での記述方法を教えてください。ありがとうございます。

編集:

私はこのようにコードを書くことができます:

def check(func):
    def checked(self):
        if not self.start:
            return
        func(self)
    return checked

class myclass:
    def __init__(self):
        self.start = False

    @check
    def doA(self):
        print('A')

    @check
    def doB(self):
        print('B')


a = myclass()

a.doA()
a.doB()

a.start = True

a.doA()
a.doB()

しかし、それは良い習慣ではないと思います。クラス内でcheckメソッドを定義したいと思います。

4

2 に答える 2

62

これが常に完全に必要なわけではないと思いますが、クラス内でデコレータを作成する方法は次のとおりです。selfメソッドが後でバインドされる方法のため、もう少し面倒です。通常、プレーンな関数デコレータを使用すれば、それについて心配する必要はありません。

要件は次のとおりです。

  1. デコレータは、それを使用するメソッドの前に最初に定義する必要があります
  2. functools.wrapsバインドされたメソッドを適切に保持するために使用する必要があります

例:

from functools import wraps

class myclass:
    def __init__(self):
        self.start = False

    def _with_check(f):
        @wraps(f)
        def wrapped(inst, *args, **kwargs):
            if inst.check():
                return
            return f(inst, *args, **kwargs)
        return wrapped

    def check(self):
        return self.start

    @_with_check
    def doA(self):
        print('A')

    @_with_check
    def doB(self):
        print('B')

クラス外で他の誰かが使用する必要のあるものではないため、保護されたメンバーにしました。check()そして、それはそれ自体で使用するためのあなたの公の呼びかけをまだ保存します。デコレータは、ターゲットメソッドを呼び出す前に、最初に呼び出しをラップするだけです。

于 2012-12-13T03:22:48.650 に答える
1

クラスで呼び出されるメソッドの数またはすべてを変更する必要があるが、その動作の変更をそのクラスとそのサブクラスにのみ適用したい場合は、代わりに__getattr__()and/orを使用して動作を実行してください。__getattribute__()

于 2012-12-13T03:24:36.297 に答える