views:

204

answers:

2

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 relies decorator 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.

+4  A: 

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'
mykhal
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.
Peter Hansen
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
mykhal
@(Peter Hansen) .. however, there's no decorator module in python 2.6 either
mykhal
+3  A: 

It works when @classmathod 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'
As a rule, `classmethod` and `staticmethod` apply a special kind of magic and have to be called last.
THC4k