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

16,585

Solution 1

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'

Solution 2

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'

Solution 3

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'
Share:
16,585
user238424
Author by

user238424

Updated on June 08, 2022

Comments

  • user238424
    user238424 about 2 years

    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.

    • gahooa
      gahooa over 14 years
      Why are you calling function(*args) INSIDE the decorator? It's job is to simply return a function (in your case, unmodified).
    • Admin
      Admin over 14 years
      gahooa: because that's one way 'decorator' (what he imports, not the language construct) works, see pypi.python.org/pypi/decorator.
    • mykhal
      mykhal over 14 years
      @taldor you have decorator module in py 2.6 ?
    • user238424
      user238424 over 14 years
      @mykhal: I installed it separately.
  • Peter Hansen
    Peter Hansen over 14 years
    I'm not sure you realized, but the "decorator" package he's using does the same thing as the construct with "wrapper". The only difference between your snippets is the order of applying the decorators in My_class. You might clarify that in the answer to explain why it fixes things.
  • mykhal
    mykhal over 14 years
    Thanks for a correction. I was playing with the problem in py3k, where the decorator module is missing. I meant my reply to be the quick one, and was sure that someone will post the better answer with detailed explanation
  • Jochen Ritzel
    Jochen Ritzel over 14 years
    As a rule, classmethod and staticmethod apply a special kind of magic and have to be called last.
  • mykhal
    mykhal over 14 years
    @(Peter Hansen) .. however, there's no decorator module in python 2.6 either
  • Nicolas Fonteyne
    Nicolas Fonteyne over 2 years
    Keep in mind that this is not 100% interchangeable. Moving the builtin decorators up may affect characteristics of the result method itself, e.g. if print_function_name was a decorating class, the outstanding type of the result method would be affected by the overruling builtin decorator