2017-01-30 5 views
0

私は現在、関数をクラスにラップするデコレータを持っています。メソッドのクラスを返すデコレータを使用していますか?

(私たちは現在、各非同期呼び出しが定型コードのトンを持つクラスとして定義されているこの奇妙な、カスタムの非同期フレームワークを使用している。私の考えはただの関数を飾るし、適切なクラスを返すようにしました。)

このデコレータは、クラス外の関数でうまく動作します。しかし、メソッドでそれを使用する場合、引数は暗黙的に渡されることはなく、理由はわかりません。ここで

は、私はちょうどそう__init__が呼び出されていないクラスを返す、一緒に

from __future__ import print_function 

import functools 


def test_wrap(func): 
    @functools.wraps(func) 
    def wrapper(*args, **kwargs): 
     print("Args:", args) 
     print("Kwargs:", kwargs) 
     func(*args, **kwargs) 
    return wrapper 


def test_class_wrap(func): 
    """Return a Command object for use with the custom framework we are using.""" 
    @functools.wraps(func, assigned=('__name__', '__module__'), updated=()) 
    class Command(object): 
     def __init__(self, *args, **kwargs): 
      print("Args:", args) 
      print("Kwargs:", kwargs) 
      func(*args, **kwargs) 

    return Command 


class MyObject(object): 

    def __init__(self): 
     self.value = 100 

    @test_wrap 
    def foo(self): 
     print(self.value) 

    @test_class_wrap 
    def bar(self): 
     print(self.value) 


if __name__ == '__main__': 
    obj = MyObject() 
    obj.foo() 

    print() 
    obj.bar(obj) # works 
    # obj.bar() # TypeError: bar() takes exactly 1 argument (0 given) 
    # Why is self implicitly passed as an argument like with outher methods? 

# Output 
# Args: (<__main__.MyObject object at 0x7fe2bf9bb590>,) 
# Kwargs: {} 
# 100 

# Args: (<__main__.MyObject object at 0x7fe2bf9bb590>,) 
# Kwargs: {} 
# 100 
+0

。 。手動で行った場合、これがどのように機能するかを考えてください。デコレータがなければ、あるクラスを別のクラスに入れ子にしたコードを書いていましたか?もしそうなら、どうしたのですか?クラスはメソッドではないので、メソッドをクラスに置き換えるデコレータを使用すると、他のクラスの中にクラスが存在することになります。これはPythonではやや珍しい状況です。デコレータを使わずに 'MyObject'と' bar'を "手動で"書く方法の例を見せてもらえますか? – BrenBarn

+0

この質問は、なぜ 'self'が' bar'に暗黙的に渡されないのかにもっと焦点を当てています。上のコードは、実際の使用ではなく、問題を再現します。私は、例を追加しようとすることができますが、それは多くの意味を理解することを期待しないでください – Shatnerz

+0

あなたのクラスのインスタンスがないため、自己が渡されない理由です。 'self'はインスタンスを参照するので、インスタンス上でメソッドを呼び出すときだけ渡すことができますが、' obj.bar'は 'Command'と呼ばれる*クラス*です。 Commandクラスを別々に書いて、 'Command()'を呼び出そうとすると、同じエラーが発生します。 – BrenBarn

答えて

1

test_class_wrapない何も置くことができなかった最高の一例です。 argsとkwargsを渡す関数でクラスをラップしようとしてください。

def test_class_wrap(func): 
    """Return a Command object for use with the custom framework we are using.""" 
    @functools.wraps(func, assigned=('__name__', '__module__'), updated=()) 
    def wrapper(*args, **kwargs): 
     class Command(object): 
      def __init__(self, *args, **kwargs): 
       print("Args:", args) 
       print("Kwargs:", kwargs) 
       func(*args, **kwargs) 
     return Command(*args, **kwargs) 
    return wrapper 

... 

if __name__ == '__main__': 
    obj = MyObject() 
    obj.foo() 

    print() 
    obj.bar() 
+0

これは "修正"するかもしれないと思いますが、その方法ははっきりしません。これは単に 'obj.bar()'がCommandクラスを返すことを意味するのに対し、 'obj.bar'の値はCommandクラスです。したがって、 'obj.bar()'は何もしません。それはクラスを返すだけです。 – BrenBarn

+0

私はこれがちょうど私が必要だったと確信しています。それは私の既存のすべてのテストにも合格します。 @BrenBarn目標は、 'bar()'を呼び出すときにクラスをインスタンス化することでした。そのくそった、明らかではないデザインですが、私はそれを変更することについてあまり言いません。だからこそ、私はすべてを包み込み、対処しやすくしています。 – Shatnerz

関連する問題