2011-01-18 7 views
9

私は下のクラスMyWrapperでインスタンスメソッドの呼び出しをインターセプトするための方法を探しています:私はすべての関数呼び出しは、私のラッパークラスを通じて行い傍受したいインスタンスメソッド呼び出しをインターセプトするには?

class SomeClass1: 
    def a1(self): 
     self.internal_z() 
     return "a1" 
    def a2(self): 
     return "a2" 
    def internal_z(self): 
     return "z" 

class SomeClass2(SomeClass1): 
    pass 

class MyWrapper(SomeClass2): 

    # def INTERCEPT_ALL_FUNCTION_CALLS(): 
    #  result = Call_Original_Function() 
    #  self.str += result 
    #  return result 


    def __init__(self): 
     self.str = '' 
    def getFinalResult(self): 
     return self.str 

x = MyWrapper() 
x.a1() 
x.a2() 

。私のラッパークラスでは、すべての結果文字列を追跡したいと思います。

result = x.getFinalResult() 
print result == 'a1a2' 

答えて

6

いくつかの迅速かつ汚いコード:

class Wrapper: 
    def __init__(self, obj): 
     self.obj = obj 
     self.callable_results = [] 

    def __getattr__(self, attr): 
     print("Getting {0}.{1}".format(type(self.obj).__name__, attr)) 
     ret = getattr(self.obj, attr) 
     if hasattr(ret, "__call__"): 
      return self.FunctionWrapper(self, ret) 
     return ret 

    class FunctionWrapper: 
     def __init__(self, parent, callable): 
      self.parent = parent 
      self.callable = callable 

     def __call__(self, *args, **kwargs): 
      print("Calling {0}.{1}".format(
        type(self.parent.obj).__name__, self.callable.__name__)) 
      ret = self.callable(*args, **kwargs) 
      self.parent.callable_results.append(ret) 
      return ret 

class A: 
    def __init__(self, val): self.val = val 
    def getval(self): return self.val 

w = Wrapper(A(10)) 
print(w.val) 
w.getval() 
print(w.callable_results) 

が徹底されないかもしれないが、まともな出発点となる可能性があり、私は推測します。

+0

どうもありがとう!私が望んでいたように素晴らしい作品です! –

+1

:-)知っているのは素晴らしいこと - あなたは歓迎しています。その後、 "受け入れられた" として:) – Shadikka

2

あなたはデコレータでインスタンス化時間をあなたの方法をラップできます。あなたはhellobyeを呼び出す場合

#!/usr/bin/env python 

import inspect 

def log(func): 
    def _logged(*args, **kw): 
     print "[LD] func", func.__name__, "called with:", args, kw 
     result = func(*args, **kw) 
     print "[LD] func", func.__name__, "returned:", result 
     return result 
    return _logged 

class A(object): 
    def __init__(self): 
     for x in inspect.getmembers(self, (inspect.ismethod)): 
      if not x[0].startswith('__'): 
       setattr(self, x[0], log(getattr(self, x[0]))) 

    def hello(self): 
     print "Hello" 

    def bye(self): 
     print "Bye" 
     return 0 

さて、コールが最初logを通過:あなたが何をしたいか

a = A() 
a.hello() 
a.bye() 

# [LD] func hello called with:() {} 
# Hello 
# [LD] func hello returned: None 
# [LD] func bye called with:() {} 
# Bye 
# [LD] func bye returned: 0 
2

ですthis questionと非常によく似ています。あなたが逆の順序であなたのコード例を取る必要があります 、私は、メソッド呼び出しの戻り値を記録し、あなたがそれを継承を見たいクラスを作成するクラスを作成する意味します。 いくつかのマイナーな変更により、この

class RetValWatcher(object): 
    def __init__(self): 
     self.retvals = [] 

    def __getattribute__(self, name): 
     attr = super(RetValWatcher, self).__getattribute__(name) 
     if callable(attr): 
      def wrapped(*args, **kwargs): 
       retval = attr(*args, **kwargs) 
       self.retvals.append(retval) 
       return retval 
      return wrapped 
     else: 
      return attr 

    def getFinalRestult(self): 
     return ''.join(self.retvals) 

class MyClass(RetValWatcher): 
    def a(self): 
     self.internal_z() 
     return 'a1' 

    def b(self): 
     return 'b1' 

    def internal_z(self): 
     return 'z' 

x = MyClass() 
x.a() 
x.b() 
print x.getFinalResult() 
#'za1b1' 

のようなものを与えることになる、この方法はまた、すべてのRetValWatcherインスタンス間の戻り値を記録することができるようになります。

編集:特異点さんのコメント

EDIT2によって提案された追加の変更:attrが(再びTHX特異点)メソッドではないケースを処理するのを忘れ

+0

+1の答えをタグ付けしてください、私はもっとこの方法を好きですが、私はいくつかの発言を持っている:1) 'retvalsを置き換える= []' self.retvals 'と= []'、2)でOP 'x.getFinalResultの場合は、()' 3)私はそれが 'inspect.ismethod'かを'使用することをお勧めだと思い、__za1a2__は__a1a2__ない返されます(ATTR) 'の代わりにはhasattr'の呼び出し可能(ATTR、 '__call __') '。 – mouad

+0

行方不明の自己はただ監督だったが、あなたは他の2ポイントのために正しいです。編集しました;) – MatToufoutu

+0

ああもう一度申し訳ありません。あなたは他の '忘れ:'呼び出し可能ならば(ATTR)の戻りattr'を: 'あなたがあいまいな属性のコールにしたくないので:) – mouad

関連する問題