Get the class name of a decorated class method

This is not easily possible. If you added self as a first parameter of the inner function you could use self.__class__.__name__ to access the class name, but then it would break when decorating a classless function without arguments (and if it had arguments, it would consider the first argument as self).

So unless there is a way to determine if a function has been called in an object context or not what you want do do is not possible.

Btw.. for what do you need that? It sounds like something which can be solved in a better way.


a simple version:

def print_my_location(func):
    def wrapper(*args, **kwargs):
        print(f'[{func.__module__}::{func.__qualname__}]: ')
        return func(*args, **kwargs)

    return wrapper

In fact, you can use inspect module to get the signature of a function, and supposing that you are following the convention of referring to the class object by the first argument 'self', you can do the following :

import inspect  
def print_name(*_args):
    def _print_name(fn):
        def wrapper(*args, **kwargs):
            try :
                is_method   = inspect.getargspec(fn)[0][0] == 'self'
            except :
                is_method   = False

            if is_method :
                name    = '{}.{}.{}'.format(fn.__module__, args[0].__class__.__name__, fn.__name__)
            else :
                name    = '{}.{}'.format(fn.__module__, fn.__name__)

            print (name)
            return  fn(*args,**kwargs)
        return wrapper
    return _print_name

this will print the method module, class and name or just the module and name, if this is a function

From python 3.3 onward, fn.__qualname__ can be used to get the qualified name of the function/method.

def print_name(*args):
     def _print_name(fn):
         def wrapper(*args, **kwargs):
             print('{}.{}'.format(fn.__module__, fn.__qualname__))
             return fn(*args, **kwargs)
         return wrapper
     return _print_name

This works fine with both functions and methods :

In [1]: class A():
...:     @print_name()
...:     def a():
...:         print('Hi from A.a')
In [2]: A.a()
    __main__.A.a
    Hi from A.a

In [25]: @print_name()
    ...: def b():
    ...:     print('Hi from b')
    ...: 
In [26]: b()
    __main__.b
    Hi from b