Pythonのメソッドデコレータの引数としてクラスインスタンス変数を使用するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/1231950

  •  22-07-2019
  •  | 
  •  

質問

クラスインスタンス変数をPythonのメソッドデコレータの引数として使用するにはどうすればよいですか? 以下は、私がやろうとしていることを示す最小限の例です。デコレータ関数がインスタンスへの参照にアクセスできないため、明らかに失敗します。デコレータから参照にアクセスする方法がわかりません。

def decorator1(arg1):
    def wrapper(function):
        print "decorator argument: %s" % arg1
        return function
    return wrapper

class Foo(object):
    def __init__(self, arg1):
        self.var1 = arg1

    @decorator1(self.var1)
    def method1(self):
        print "method1"

foo = Foo("abc")
foo.method1()
役に立ちましたか?

解決

機能しません。デコレータは、クラスの作成時間中に呼び出されます。これは、インスタンスが作成されるずっと前です(これが発生する場合は if )。あなたの「デコレーター」がインスタンスが必要な場合は、「装飾」を行う必要があります。インスタンス化時:

def get_decorator(arg1):
    def my_decorator(function):
        print "get_decorator argument: %s" % arg1
        return function
    return my_decorator

class Foo(object):
    def __init__(self, arg1):
        self.var1 = arg1
        self.method1 = get_decorator(self.var1)(self.method1)

    def method1(self):
        print "method1"

foo = Foo("abc")
foo.method1()

関数の名前を意味に従って変更したことに注意してください。実際の「デコレータ」、つまりメソッドを(潜在的に)変更する関数は、 decorator1 ではなく、 wrapper です。

他のヒント

あなたの“ワーパー” functionは、実際にはワーパーではなく、デコレータです。あなたの“ decorator1” functionはデコレータコンストラクタです。実行時にself.var1にアクセスしたい場合は、デコレーターではなくワーパーを作成する必要があります:

def decorator(function):
  def wrapper(self,*args,**kwargs):
    print "Doing something with self.var1==%s" % self.var1
    return function(self,*args,**kwargs)
  return wrapper

class Foo(object):
  def __init__(self, arg1):
    self.var1 = arg1

  @decorator
  def method1(self):
    print "method1"

foo = Foo("abc")
foo.method1()

より一般的なデコレータが必要な場合は、呼び出し可能なクラスを宣言することをお勧めします:

class decorator:
  def __init__(self,varname):
      self.varname = varname
  def __call__(self,function):
    varname=self.varname
    def wrapper(self,*args,**kwargs):
      print "Doing something with self.%s==%s" % (varname,getattr(self,varname))
      return function(self,*args,**kwargs)
    return wrapper

使用方法:

  @decorator("var1")

デコレータはクラスが定義されると実行されるため、インスタンス変数を渡すことはできません。

昔はこれをどのように行っていましたか。

class Foo(object):
    def __init__(self, arg1):
        self.var1 = arg1

    def method1(self):
        self.lock()
        try:
            self.do_method1()
        except Exception:
            pass # Might want to log this
        finally:
            self.unlock()

    def do_method1(self):
        print "method1"

    def lock(self):
        print "locking: %s" % self.arg1

    def unlock(self):
        print "unlocking: %s" % self.arg1

今、サブクラスは、 do_method1 をオーバーライドするだけで" wrapping"の利点を得ることができます。 with ステートメントなしで、古い方法で完了します。

はい、時間がかかります。ただし、魔法も含まれていません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top