Why can @decorator not decorate a staticmethod or a classmethod?

Question:

Why can decorator not decorate a staticmethod or a classmethod?

from decorator import decorator

@decorator
def print_function_name(function, *args):
    print '%s was called.' % function.func_name
    return function(*args)

class My_class(object):
    @print_function_name
    @classmethod
    def get_dir(cls):
        return dir(cls)

    @print_function_name
    @staticmethod
    def get_a():
        return 'a'

Both get_dir and get_a result in AttributeError: <'classmethod' or 'staticmethod'>, object has no attribute '__name__'.

Why does decorator rely on the attribute __name__ instead of the attribute func_name? (Afaik all functions, including classmethods and staticmethods, have the func_name attribute.)

Edit: I’m using Python 2.6.

Asked By: user238424

||

Answers:

Is this what you wanted?

def print_function_name(function):
    def wrapper(*args):
        print('%s was called.' % function.__name__)
        return function(*args)
    return wrapper

class My_class(object):
    @classmethod
    @print_function_name
    def get_dir(cls):
        return dir(cls)

    @staticmethod
    @print_function_name
    def get_a():
        return 'a'
Answered By: mykhal

It works when @classmethod and @staticmethod are the top-most decorators:

from decorator import decorator

@decorator
def print_function_name(function, *args):
    print '%s was called.' % function.func_name
    return function(*args)

class My_class(object):
    @classmethod
    @print_function_name
    def get_dir(cls):
        return dir(cls)
    @staticmethod
    @print_function_name
    def get_a():
        return 'a'
Answered By: user238424

classmethod and staticmethod return descriptor objects, not functions. Most decorators are not designed to accept descriptors.

Normally, then, you must apply classmethod and staticmethod last when using multiple decorators. And since decorators are applied in “bottom up” order, classmethod and staticmethod normally should be top-most in your source.

Like this:

class My_class(object):
    @classmethod
    @print_function_name
    def get_dir(cls):
        return dir(cls)

    @staticmethod
    @print_function_name
    def get_a():
        return 'a'
Answered By: wberry
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.