2016-03-26 14 views
1

以下は、自己(現在のオブジェクトインスタンス)Pythonのデコレータは、自己

class Test(object): 
    def __init__(self): 
     self.x = 5 

    def _change_x(self): 
     print "in _change_x" 
     def decorator(f): 
      print "in decorator" 
      def wrapped(*args, **kwargs): 
       print "in wrapped" 
       print args, kwargs 
       self.x = 8 
       f(*args, **kwargs) 
      return wrapped 
     return decorator 

    @_change_x 
    def print_x(self): 
     print "in print_x, x: %d" % self.x 
     return self.x 

if __name__ == "__main__": 
    test = Test() 
    print "Initial value for x: %d" % test.x 
    print "Test if it changed? x: %d" % test.print_x() 

変更することができ、クラスメソッドのデコレータを持って私のテストコードでありますデコレータにラップされた内部メソッドが呼び出されていません。私のテストコードで間違いを指摘する手助けをすることができます。 クラス内で定義されたこの種のデコレータが必要で、呼び出し時にクラスメンバを変更するために、そのクラスのメソッドをいくつかデコレートするために使用されます。

+0

各関数呼び出しの前にクラスメンバ(そのインスタンス用)を変更する方法は、デコレータ以外の方法を提案できますか?私は可読性のために修正が不透明であることを望んでいます。なぜ、私がクラスメソッドの始めにそれらを修正していないのですか? – RPM

+0

関数呼び出しの直前に何を変更したいのかを理解するのは少し難しいです...私は手元に問題があるかどうかはわかりませんが、これは私ができるあらゆるケースの直感的なデザインパターンのようです思うようにしてください(これは現在のユースケースではありません;-))。 – mgilson

+0

@mgilsonは、多くのメソッド呼び出しが非常に強力なデバッグツールとなる前に余分なステップを挿入しています。単純に 'print f'はプログラムの全過程を通してどのメソッドが呼び出されているかを示します。 –

答えて

2

まず、あなたのコード仕事... _change_xが呼び出された時点で

は、クラスがまだ建設中でないので、のいずれかのインスタンスが存在することはできません理由を考えることができますクラス。このため、あなたのself引数は誤解を招きます。呼び出されると、selfは実際には関数print_xです。明らかにselfに項目を追加すると、selfTestのインスタンスではないため、Testのインスタンスは変更されません。 つまり、クラス内にデコレータ関数を定義することについて特別なことは何もありません。唯一のことは、他の時に呼び出すことができる名前空間に関数_change_xを追加することです。

これをどのようにして取得できますか?さて、答えは_change_xが唯一の装飾方法であることを認識することです。その場合には、ラッパー関数の最初の引数は(単に通常の方法のように)selfとなりますので、我々はそこにドロップし、wrappedの内側にそれに取り組むことができます。これは動作します:

class Test(object): 

    def __init__(self): 
     self.x = 5 

    def _change_x(f): 
     print "in _change_x" 
     def wrapped(self, *args, **kwargs): 
      print "in wrapped" 
      print args, kwargs 
      self.x = 8 
      return f(self, *args, **kwargs) 
     return wrapped 

    @_change_x 
    def print_x(self): 
     print "in print_x, x: %d" % self.x 
     return self.x 

if __name__ == "__main__": 
    test = Test() 
    print "Initial value for x: %d" % test.x 
    print "Test if it changed? x: %d" % test.print_x() 

しかし、クラス内にデコレータを定義する必要はまったくないことが判明しました。私が先に言ったように、すべての後、 - ...クラスにそれを置くことについての特別なことは何もありません:

def _change_x(f): 
    print "in _change_x" 
    def wrapped(self, *args, **kwargs): 
     print "in wrapped" 
     print args, kwargs 
     self.x = 8 
     return f(self, *args, **kwargs) 
    return wrapped 


class Test(object): 

    def __init__(self): 
     self.x = 5 

    @_change_x 
    def print_x(self): 
     print "in print_x, x: %d" % self.x 
     return self.x 

if __name__ == "__main__": 
    test = Test() 
    print "Initial value for x: %d" % test.x 
    print "Test if it changed? x: %d" % test.print_x() 
+0

"私はこの種のデコレータをclass_で定義したがっています"とは、OPが具体的にクラス定義の中でデコレータを必要としていると示唆しています –

+0

@ TadhgMcDonald-Jensen - )。 OPが質問/コメントを更新すればもっと明確になるでしょうか? – mgilson

0

問題が_change_xデコレータ自体があり、そしてラッパーは、引数としての自己を取る必要があるということです:あなたは、おそらくどちらかがクラスのスコープから削除したいので、これはしかし以来、クラス定義に入れて紛らわしいかもしれ

def _change_x(f): 
    print "in _change_x decorator" 
    def wrapped(self,*args, **kwargs): 
     print "in wrapped" 
     print args, kwargs 
     self.x = 8 
     f(self,*args, **kwargs) 
     #maybe return f(*args,**kw)? 
    return wrapped 

、デコレータされ、それを使用した後、インスタンス上の方法ではありませんかクラススコープの外に定義してください(同じように動作します)

編集:if yクラス定義の_change_xを定義し、クラス定義の最後に_change_x = staticmethod(_change_x)を追加すると、クラス定義の後に静的メソッドとして使用できるようになりますが、同じスコープで完了するまではこれを行うことはできません。 (@_change_x.__get__(0)が本当に不要な場合を除いて)

関連する問題