2009-11-05 7 views
7

デコレータがクラスメソッドで使用するためにデコレータを作成するとき、デコレータ機構が関数/クロージャではなくクラスであるときに問題が発生します。クラスフォームが使用されるとき、私のデコレータはバインドされたメソッドとして扱われません。デコレータ機構がクラスの場合、クラスメンバーのPythonデコレータが失敗する

一般的に私はデコレータに関数形式を使用することをお勧めしますが、この場合、必要なものを実装するために既存のクラスを使用する必要があります。

これは、python-decorator-makes-function-forget-that-it-belongs-to-a-classに関連しているようですが、なぜ機能フォームでうまく機能するのですか?

ここでは、すべての機能を表示するための最も簡単な例を示します。コードの量については申し訳ありません:

def decorator1(dec_param): 
    def decorator(function): 
     print 'decorator1 decoratoring:', function 
     def wrapper(*args): 
      print 'wrapper(%s) dec_param=%s' % (args, dec_param) 
      function(*args) 
     return wrapper 
    return decorator 

class WrapperClass(object): 
    def __init__(self, function, dec_param): 
     print 'WrapperClass.__init__ function=%s dec_param=%s' % (function, dec_param) 
     self.function = function 
     self.dec_param = dec_param 

    def __call__(self, *args): 
     print 'WrapperClass.__call__(%s, %s) dec_param=%s' % (self, args, self.dec_param) 
     self.function(*args) 

def decorator2(dec_param): 
    def decorator(function): 
     print 'decorator2 decoratoring:', function 
     return WrapperClass(function, dec_param) 
    return decorator 

class Test(object): 
    @decorator1(dec_param=123) 
    def member1(self, value=1): 
     print 'Test.member1(%s, %s)' % (self, value) 

    @decorator2(dec_param=456) 
    def member2(self, value=2): 
     print 'Test.member2(%s, %s)' % (self, value) 

@decorator1(dec_param=123) 
def free1(value=1): 
    print 'free1(%s)' % (value) 

@decorator2(dec_param=456) 
def free2(value=2): 
    print 'free2(%s)' % (value) 

test = Test() 
print '\n====member1====' 
test.member1(11) 

print '\n====member2====' 
test.member2(22) 

print '\n====free1====' 
free1(11) 

print '\n====free2====' 
free2(22) 

出力:

decorator1 decoratoring: <function member1 at 0x3aba30> 
decorator2 decoratoring: <function member2 at 0x3ab8b0> 
WrapperClass.__init__ function=<function member2 at 0x3ab8b0> dec_param=456 
decorator1 decoratoring: <function free1 at 0x3ab9f0> 
decorator2 decoratoring: <function free2 at 0x3ab970> 
WrapperClass.__init__ function=<function free2 at 0x3ab970> dec_param=456 

====member1==== 
wrapper((<__main__.Test object at 0x3af5f0>, 11)) dec_param=123 
Test.member1(<__main__.Test object at 0x3af5f0>, 11) 

====member2==== 
WrapperClass.__call__(<__main__.WrapperClass object at 0x3af590>, (22,)) dec_param=456 
Test.member2(22, 2)  <<<- Badness HERE! 

====free1==== 
wrapper((11,)) dec_param=123 
free1(11) 

====free2==== 
WrapperClass.__call__(<__main__.WrapperClass object at 0x3af630>, (22,)) dec_param=456 
free2(22) 
+1

質問の名前を変更することをお勧めします。これは実際にデコレータには関係しませんが、むしろ関数オブジェクトをクラスメソッドとして追加することです。 – Casebash

+0

一般的に(必ずしもそうではありませんが)、質問がそれほど長い場合、問題を切り分けて簡略化することができます。たとえば、クラスに手動で注釈を付けることを試みた場合、デコレータとは何の関係もなく、おそらくそのコードをすべて入力するよりも早いでしょう – Casebash

答えて

10

あなたWrapperClassは、ディスクリプタ(!ちょうど関数のようである)、すなわち、供給適切な特殊な方法__get____set__する必要があります。 This how-to guideはあなたが知る必要があるすべてを教えています! - )

関連する問題