9

他のクラスのメソッドをデコレートするデコレータクラスを実装しようとしています。ただし、デコレータで使用可能なdecoratedメソッドを保持するクラスが必要です。どこにも見つからないようです。

次に例を示します。

class my_decorator(object):

  def __init__(self, arg1, arg2):
    print(self.__class__.__name__ + ".__init__")
    self.arg1 = arg1
    self.arg2 = arg2

  def __call__(self, my_callable):
    print(self.__class__.__name__ + ".__call__")
    print(type(my_callable))
    self.my_callable = my_callable
#    self.my_callable_method_class = ?where to get this?

    def function_wrapper(*args, **kwargs):
      print(self.__class__.__name__ + ".function_wrapper")
      print(self.arg1)
      self.my_callable.__call__(*args, **kwargs)
      print(self.arg2)

    return function_wrapper


class MyClass(object):

  @my_decorator(arg1="one", arg2="two")
  def decorated_method(self):
    print(self.__class__.__name__ + ".decorated_method")
    print(type(self.decorated_method))
    print("hello")


m = MyClass()
m.decorated_method()

これを印刷します:

my_decorator.__init__
my_decorator.__call__
<type 'function'>
my_decorator.function_wrapper
one
MyClass.decorated_method
<type 'instancemethod'>
hello
two

デコレータクラスでは、呼び出し可能オブジェクトは関数型ですが、クラス自体の内部ではインスタンスメソッド型です。instancemethodからim_classを取得できますが、関数にはそのようなものはありません。

デコレータ内からdecoratedメソッドを含むクラスを取得するにはどうすればよいですか?

私はこれを行うことができます:

class my_decorator(object):

  def __init__(self, cls, arg1, arg2):

.
.

class MyClass(object):

  @my_decorator(cls=MyClass, arg1="one", arg2="two")
  def decorated_method(self):

.
.

しかし、それは冗長であり、良くないので、私はそれをしたくありません。

または、これを別の方法で実装する必要がありますか?基本的に、デコレータに対していくつかの引数が必要です。また、デコレータのdecoratedメソッドのクラスが必要です。

4

3 に答える 3

3

あなたはクラスを飾ることができます:

@decorate
class MyClass(object):

  @my_decorator(arg1="one", arg2="two")
  def decorated_method(self):

外側のデコレータを使用して、クラス引数を内側に送信します。


クラスが存在する前にクラスにアクセスする必要があるため、プロポーザルは機能しません。クラスを定義するときは、最初にその本体内でコードを実行し(関数の定義など)、次に結果のスコープをそのクラスに割り当てます__dict__decorated_methodしたがって、定義されている時点では、MyClassまだ存在していません。

于 2012-11-15T08:57:30.050 に答える
1

これが機能する改訂版です。

# This holds all called method_decorators
global_method_decorator_list = []

class class_decorator(object):
  def __init__(self, arg1, arg2):
    print(self.__class__.__name__ + ".__init__")
    self.arg1 = arg1
    self.arg2 = arg2

  def __call__(self, my_class):
    print(self.__class__.__name__ + ".__call__")
    print(repr(my_class))
    print(my_class.__name__)
    self.cls = my_class
    class_decorators[my_class] = self
    self.my_class = my_class

    # Call each method decorator's second_init()
    for d in global_method_decorator_list:
      d._method_decorator_.second_init(self, my_class)

    def wrapper(*args, **kwargs):
      print(self.__class__.__name__ + ".wrapper")
      print(self.arg1)
      retval = self.my_class.__call__(*args, **kwargs)
      print(self.arg2)
      return retval

    return wrapper


class method_decorator(object):
  def __init__(self, arg1, arg2):
    print(self.__class__.__name__ + ".__init__")
    self.arg1 = arg1
    self.arg2 = arg2

  def __call__(self, my_callable):
    print(self.__class__.__name__ + ".__call__")
    print(repr(my_callable))
    self.my_callable = my_callable

    # Mark the callable and add to global list
    my_callable._method_decorator_ = self
    global_method_decorator_list.append(my_callable)

    def wrapper(*args, **kwargs):
      print(self.__class__.__name__ + ".wrapper")
      print(self.arg1)
      retval=self.my_callable.__call__(*args, **kwargs)
      print(self.arg2)
      return retval

    return wrapper

  def second_init(self, the_class_decorator, the_class):
    print(self.__class__.__name__ + ".second_init")
    print("The Class: " + repr(the_class))**


@class_decorator(arg1="One", arg2="Two")
class MyClass(object):

  @method_decorator(arg1="one", arg2="two")
  def decorated_method(self):
    print(self.__class__.__name__ + ".decorated_method")
    print(type(self.decorated_method))
    print("hello")


m = MyClass()
m.decorated_method()

出力は次のようになります。

class_decorator.__init__
method_decorator.__init__
method_decorator.__call__
<function decorated_method at 0x3063500>
class_decorator.__call__
<class '__main__.MyClass'>
MyClass
method_decorator.second_init
The Class: <class '__main__.MyClass'>
class_decorator.wrapper
One
Two
method_decorator.wrapper
one
MyClass.decorated_method
<type 'instancemethod'>
hello
two

違いは、クラスに個別のデコレータがあることです。クラスデコレータの呼び出し()は、各メソッドデコレータ「second_init()」メソッドを呼び出し、そこにクラスを渡します。

興味深いことに、method_decoratorの呼び出し()はclass_decoratorの呼び出しの前に呼び出されます。

于 2012-11-15T10:35:26.863 に答える
0

デコレータによって返されるオブジェクトを記述子にすると、属性ルックアップをフックして、メソッドとクラス(またはインスタンス)をリンクする他のオブジェクトを返すことができます。

メソッドスタイル記述子の場合、必要なのは__get__メソッドを実装することだけです。クラスでメソッドを検索する場合、次の2つは同等です。

m = MyClass.decorated_method
# It will actually get the object from any parent class too.  But this will do for a simple example
m = MyClass.__dict__['decorated_method'].__get__(MyClass)

そして、例えば、以下は同等です:

instance = MyClass()
m = instance.decorated_method
m = type(instance).__dict__['decorated_method'].__get__(instance, type(instance))

したがって、式instance.decorated_method(...)は実際には、__get__メソッドによって返されたオブジェクトを呼び出します。selfこれは、単純な関数オブジェクトを、暗黙の引数を追加するバインドされたメソッドオブジェクトに変換できるようにするプロセスと同じです。

この呼び出し可能オブジェクトを作成するときは、必要なすべての情報が必要です。

于 2012-11-15T09:22:52.687 に答える