Decorate the attributes to be called from the metaclass:
from functools import wraps def _log_method(val): @wraps(val) def wrapper(*a, **ka): print(val.__name__, 'is called') val(*a, **ka) return wrapper class LogMethodCalls(type): def __new__(cls, cls_name, bases, attrs): for name, attr in attrs.items(): if callable(attr): attrs[name] = _log_method(attr) return type.__new__(cls, cls_name, bases, attrs) class Foo(metaclass=LogMethodCalls): def my_method(self): pass Foo().my_method()
Warning This code only works for methods, methods that were decorated with @classmethod or @staticmethod will not be registered (because the classmethod and staticmethod not staticmethod - they are simply descriptors without data).
The following actions are used for class methods and static methods:
from functools import wraps def _log_method(val): @wraps(val) def wrapper(*a, **ka): print('calling', val.__name__) val(*a, **ka) return wrapper class LogMethodCalls(type): def __new__(cls, cls_name, bases, attrs): for name, attr in attrs.items(): if callable(attr): attrs[name] = _log_method(attr) elif isinstance(attr, (classmethod, staticmethod)): attrs[name] = type(attr)(_log_method(attr.__func__)) return type.__new__(cls, cls_name, bases, attrs) class Foo(metaclass=LogMethodCalls): def my_instance_method(self): pass @classmethod def my_class_method(cls): pass @staticmethod def my_static_method(): pass Foo().my_instance_method()
They have __func__ attributes that we can decorate.
Please note that you will need to use
class Foo(object): __metaclass__ = LogMethodCalls
in Python 2.