2016-06-15 5 views

答えて

5

いいえ、これを行うにはクラスにフックがありません。メソッドは属性でもですが、インスタンス上の関数オブジェクトにアクセスするときに生成されるという点では多少異なります。機能はdescriptorsです。メソッドオブジェクトへ

コールは、メソッドオブジェクトを生成するとは別のステップです:

>>> class Foo(object): 
...  def bar(self): 
...   return 'bar method on Foo' 
... 
>>> f = Foo() 
>>> f.bar 
<bound method Foo.bar of <__main__.Foo object at 0x100777bd0>> 
>>> f.bar is f.bar 
False 
>>> stored = f.bar 
>>> stored() 
'bar method on Foo' 

ディスクリプタプロトコルを起動するobject.__getattribute__() methodの作業ですので、あなたがすることにフックができメソッドが生成されたときを参照してくださいが、を呼び出すを生成すると、を呼び出すメソッドオブジェクトがを呼び出す必要があります。たとえば、実際のメソッドの代理を行う__call__ methodのオブジェクトを返すことができます。

しかし、呼び出されるたびにカウンタをインクリメントするデコレータで各メソッドを飾る方が簡単です。あなたはまだあなたのクラス内のすべての機能にこれを適用する必要があると思い

from functools import wraps 

def method_counter(func): 
    @wraps(func) 
    def wrapper(self, *args, **kwargs): 
     self.methodCalls += 1 
     return func(self, *args, **kwargs) 
    return wrapper 

:あなたが一緒にselfに合格する必要がありますので、それは、バインドされているデコレータが前に機能に適用さを考慮してください。あなたがカウントしたいすべてのメソッドにこれを手動で適用することができます:

class MyClass(object): 
    def __init__(self): 
     self.foo = "foo" 
     self.bar = "bar" 
     self.methodCalls = 0 #tracks number of times any function method is run 

    @method_counter 
    def get_foo(self): 
     return self.foo 

    @method_counter 
    def get_bar(self): 
     return self.bar 

をしたり、メタクラスを使用することができます。

import types 

class MethodCounterMeta(type): 
    def __new__(mcls, name, bases, body): 
     # create new class object 
     for name, obj in body.items(): 
      if name[:2] == name[-2:] == '__': 
       # skip special method names like __init__ 
       continue 
      if isinstance(obj, types.FunctionType): 
       # decorate all functions 
       body[name] = method_counter(obj) 
     return super(MethodCounterMeta, mcls).__new__(mcls, name, bases, body) 

    def __call__(cls, *args, **kwargs): 
     # create a new instance for this class 
     # add in `methodCalls` attribute 
     instance = super(MethodCounterMeta, cls).__call__(*args, **kwargs) 
     instance.methodCalls = 0 
     return instance 

これはあなたのためのmethodCalls属性を設定し、すべてのデコレータのニーズの世話をします、後者のアプローチの

class MyClass(object): 
    __metaclass__ = MethodCounterMeta 
    def __init__(self): 
     self.foo = "foo" 
     self.bar = "bar" 

    def get_foo(self): 
     return self.foo 

    def get_bar(self): 
     return self.bar 

デモ:

ので、あなたのクラスはにはありません。
>>> class MyClass(object): 
...  __metaclass__ = MethodCounterMeta 
...  def __init__(self): 
...   self.foo = "foo" 
...   self.bar = "bar" 
...  def get_foo(self): 
...   return self.foo 
...  def get_bar(self): 
...   return self.bar 
... 
>>> instance = MyClass() 
>>> instance.get_foo() 
'foo' 
>>> instance.get_bar() 
'bar' 
>>> instance.methodCalls 
2 

は、上記メタクラスのみ関数(SO def文とlambda式の結果)装飾用のクラス本体の一部をオブジェクト考慮する。他の呼び出し可能なオブジェクト(functools.partialオブジェクトのような__call__メソッドを持つタイプがさらにあります)、の後に追加される関数はです。

+0

優秀な答え渡された場合にのみ付きメソッド呼び出し、または直接にカウンターの増分を持つことができる - 私が後だった正確に何を。ありがとう! – techydesigner

+0

ノーフックの声明に反対、そう – Mixone

+0

@Mixoneを行うことは完全に可能である:クラスには*直接フックは*ありません。メソッドがどのように作成されるのか、それらのオブジェクトを呼び出す方法を理解する必要があります。 –

関連する問題