2011-01-18 12 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

आप एक instanciation समय सज्जाकार के साथ अपने तरीकों लपेट सकता है:

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

आप क्या करना चाहते हैं:

#!/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 

अब अगर आप hello या bye फोन कॉल log पहले माध्यम से चला जाता 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 के साथ बदलें ' ओपी 'x.getFinalResult()' __za1a2__ __a1a2__, 3 नहीं लौटाएगा) मुझे लगता है कि 'हैस्पर (एटीआर, '__call __') के बजाय 'निरीक्षण.वाद विधि' या 'कॉल करने योग्य (एटीआर)' का उपयोग करना बेहतर है। – mouad

+0

गायब 'स्वयं' सिर्फ एक निरीक्षण था, लेकिन आप अन्य 2 अंक के लिए सही हैं। संपादित;) – MatToufoutu

+0

आह क्षमा करें; आप 'else: कॉल करने योग्य (attr) के लिए 'वापसी वापस' भूल जाते हैं: 'क्योंकि आप विशेषता कॉल को अस्पष्ट नहीं करना चाहते हैं :) – mouad

संबंधित मुद्दे