2016-11-23 58 views
5

我想裝飾所有方法在類中,我成功與此代碼,但我也試圖記錄調用運營商像* + - /,有沒有什麼方法來裝飾它們或類似getattr(self,"*")記錄通話?裝飾運營商python3.5


class Logger(object): 
    def __init__(self, bool): 
     self.bool = bool 

    def __call__(self, cls): 
     class DecoratedClass(cls): 
      def __init__(cls, *args, **kwargs): 
       super().__init__(*args, **kwargs) 

       if not(self.bool): 
        return 
       methods = [func for func in dir(cls) 
         if callable(getattr(cls, func)) 
         and not func.startswith("__class")] 
       for func in methods: 
        old_func = getattr(cls, func) 
        def decorated_function(fname, fn): 
         def loggedFunction(*args, **kwargs): 
          print("Calling {0} from {3} with params {1} and kwargs {2}".format(fname.upper(), args, kwargs, cls)) 
          return fn(*args, **kwargs) 
         return loggedFunction 
        setattr(cls, func, decorated_function(func, old_func)) 

     return DecoratedClass 

@Logger(True) 
class DummyClass(): 
    def __init__(self,foo): 
     self.foo = foo 
    def bar(self): 
     print(self.foo) 
    def __mul__(self,other): 
     print("Hello",other) 
if __name__ == '__main__': 
    a = DummyClass('hola') 
    a.method() 
    a.__mul__(a) #this is logged 
    print(a*a) #this is not logged by decorator 

回答

2

感謝Łukasz,這是一個工作腳本。

我遇到的困難是處理多個實例,並避免多次裝飾相同的類方法。爲了解決這個問題,我跟蹤了裝飾類的方法(cls.__logged)。

另一個困難是對付魔術方法,如__setattr____getattribute____repr__,...我的解決辦法是不理會他們,除了你必須在啓動(loggable_magic_methods)定義的列表。

from functools import wraps 


loggable_magic_methods = ['__mul__',] 


def is_magic_method(method): 
    return method.startswith('__') 


class Logger(object): 
    def __init__(self, bool): 
     self.bool = bool 

    def __call__(self, cls): 

     class LoggedClass(cls): 
      cls.__logged = [] 
      def __init__(instance, *args, **kwargs): 
       super().__init__(*args, **kwargs) 

       if not(self.bool): 
        return 

       methods = [funcname for funcname in dir(instance) 
          if callable(getattr(instance, funcname)) 
          and (funcname in loggable_magic_methods or not is_magic_method(funcname))] 

       def logged(method): 
        @wraps(method) 
        def wrapper(*args, **kwargs): 
         print (method.__name__, args, kwargs, cls) 
         return method(*args, **kwargs) 
        return wrapper 

       for funcname in methods: 
        if funcname in cls.__logged: 
         continue 

        if is_magic_method(funcname): 
         setattr(cls, funcname, logged(getattr(cls, funcname))) 
         cls.__logged.append(funcname) 
        else: 
         setattr(instance, funcname, logged(getattr(instance, funcname))) 
     return LoggedClass 

@Logger(True) 
class DummyClass(): 
    def __init__(self, foo, coef): 
     self.foo = foo 
     self.coef = coef 
    def bar(self): 
     print(self.foo) 
    def __mul__(self, other): 
     print(self.foo) 
     print(other.foo) 
     return self.coef * other.coef 

if __name__ == '__main__': 
    a = DummyClass('hola', 1) 
    a.bar() 
    print() 
    print(a.__mul__(a)) 
    print() 
    print(a*a) 
    print() 
    b = DummyClass('gracias', 2) 
    b.bar() 
    print() 
    print(b.__mul__(a)) 
    print() 
    print(b*a) 
2

目前正在配值的實例。您在__init__簽名中使用cls的簽名是虛假的朋友 - 實際上在這種情況下其實是老的self

如果您想重寫魔術方法,解釋器會在類對象上尋找它們,但不會在實例上尋找它們

最少例如:

class DummyClass: 
    def __init__(self, foo): 
     self.foo = foo 
    def __mul__(self, other): 
     return self.foo * other.foo 


def logged(method): 
    def wrapper(*args, **kwargs): 
     print (method.__name__, args, kwargs) 
     return method(*args, **kwargs) 
    return wrapper 

DummyClass.__mul__ = logged(DummyClass.__mul__) 


a = DummyClass(1) 
b = DummyClass(2) 
assert a * a == 1 
assert a * b == 2 
assert b * b == 4 

每個呼叫被記錄。

>>> a = DummyClass(1) 
>>> b = DummyClass(2) 
>>> assert a * a == 1 
__mul__ (<__main__.DummyClass object at 0x00000000011BFEB8>, <__main__.DummyClass object at 0x00000000011BFEB8>) {} 
>>> assert a * b == 2 
__mul__ (<__main__.DummyClass object at 0x00000000011BFEB8>, <__main__.DummyClass object at 0x00000000011BF080>) {} 
>>> assert b * b == 4 
__mul__ (<__main__.DummyClass object at 0x00000000011BF080>, <__main__.DummyClass object at 0x00000000011BF080>) {} 

我會留下一個重寫猴子修補方法給你的任務。