2011-01-18 16 views
9

Tôi đang tìm kiếm một cách để đánh chặn các cuộc gọi phương pháp dụ trong lớp MyWrapper dưới đây:Làm thế nào để đánh chặn các cuộc gọi phương thức cá thể?

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() 

Tôi muốn chặn tất cả các cuộc gọi chức năng thực hiện thông qua lớp wrapper của tôi. Trong lớp wrapper của tôi, tôi muốn theo dõi tất cả các chuỗi kết quả.

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

Trả lời

6

Một số mã nhanh chóng và dơ bẩn:

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) 

Có thể không được triệt để, nhưng có thể là một điểm khởi đầu khá, tôi đoán.

+0

Cảm ơn rất nhiều! Nó hoạt động tốt như tôi muốn! :-) –

+1

Điều cần biết - bạn được chào đón. Vui lòng gắn thẻ câu trả lời là "được chấp nhận" rồi :) – Shadikka

2

Bạn có thể quấn phương pháp của bạn với trang trí một thời gian instanciation:

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

Bây giờ nếu bạn gọi hello hoặc bye, cuộc gọi đi qua log đầu tiên:

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

Những gì bạn muốn làm là khá giống với this question. Bạn nên lấy mã ví dụ theo thứ tự ngược lại, tôi muốn tạo một lớp để ghi lại các giá trị trả về của các cuộc gọi phương thức và tạo các lớp bạn muốn xem kế thừa từ nó. nào sẽ cung cấp cho một cái gì đó như thế này

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' 

Với một số thay đổi nhỏ, phương pháp này cũng sẽ cho phép bạn ghi lại các giá trị trở lại trên tất cả các trường hợp RetValWatcher.

Edit: thêm những thay đổi được đề xuất bởi bình dị của

Edit2: quên để xử lý các trường hợp attr không phải là một phương pháp (thx dị một lần nữa)

+0

+1, tôi thích phương pháp này nhiều hơn, nhưng tôi có một số nhận xét: 1) thay thế 'retvals = []' bằng 'self.retvals = []', 2) trong trường hợp của OP 'x.getFinalResult()' sẽ trả về __za1a2__ không __a1a2__, 3) tôi nghĩ tốt hơn nên sử dụng 'inspect.ismethod' hoặc' callable (attr) 'thay vì' hasattr (attr, '__call __') '. – mouad

+0

thiếu 'bản thân' chỉ là một sự giám sát, nhưng bạn là đúng cho 2 điểm còn lại. đã chỉnh sửa;) – MatToufoutu

+0

Ahh xin lỗi lần nữa; bạn quên 'else: return attr' cho' if callable (attr): 'bởi vì bạn không muốn che khuất cuộc gọi thuộc tính :) – mouad