Python - Print method name whenever the methods of a class is called

Taken from this answer. You can use the inspect module to look at the stack for the function name to create a simple logging function. Seems like kind of a hack, but I suppose it answers the question.

import inspect

def log_call():
    print(inspect.stack()[1][3])

def my_func():
    log_call()
    # do stuff

my_func()

This will print my_func.


Decorate callable attributes from within a 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() # my_method is called

Warning: This code only works for instance methods, methods that were decorated with @classmethod or @staticmethod will not be logged (because classmethod and staticmethod objects are not callable - they're just non-data descriptors).


The following works for class methods and static methods as well:

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() # calling my_instance_method
Foo.my_class_method() # calling my_class_method
Foo.my_static_method() # calling my_static_method

They have __func__ attributes that we can decorate.


Note that you'll need to use

class Foo(object):
    __metaclass__ = LogMethodCalls

in Python 2.


You could implement a decorator:

from functools import wraps

def print_function_name(function):
    @wraps(function)
    def do_it():
        print function.__name__
        function()
    return do_it

Usage:

class MyClass(object):
    @print_function_name
    def some_function(self):
        pass

For example:

>>> my_object = MyClass()
>>> my_object.some_function()
some_function

The use of functools.wraps makes sure the function keeps its documentation and name, instead of becoming do_it.