Thanks to Εukasz, the script works here.
The difficulty I came across is to process multiple instances and avoid reusing the same class methods. To deal with this problem, I track decorated class methods ( cls.__logged ).
Another difficulty is considering magic methods like __setattr__ , __getattribute__ , __repr__ , ... My solution is to ignore them, except for the list you have to define at startup ( 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)
source share