How to intercept instance method calls?
我正在寻找一种方法来截获类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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() |
我想截取通过包装类进行的所有函数调用。在包装类中,我希望跟踪所有结果字符串。
1 2 | result = x.getFinalResult() print result == 'a1a2' |
号
一些快速而肮脏的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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) |
可能不是很彻底,但可能是一个不错的起点,我想。
你想做的和这个问题非常相似。您应该按照相反的顺序使用示例代码,我的意思是创建一个类来记录方法调用的返回值,并使您要监视的类从中继承。哪一个会像这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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奇点)
你可以用装饰器包装你的方法一个声明时间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/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 |
号
现在,如果您呼叫
1 2 3 4 5 6 7 8 9 10 | 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 |