56

Why can decorator not decorate a staticmethod or a classmethod in Python 2.6?

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.)

4
  • 2
    Why are you calling function(*args) INSIDE the decorator? It's job is to simply return a function (in your case, unmodified). Commented Jan 1, 2010 at 5:22
  • 6
    gahooa: because that's one way 'decorator' (what he imports, not the language construct) works, see pypi.python.org/pypi/decorator. Commented Jan 1, 2010 at 6:28
  • @taldor you have decorator module in py 2.6 ? Commented Jan 4, 2010 at 10:41
  • @mykhal: I installed it separately. Commented Jan 4, 2010 at 13:38

3 Answers 3

95

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 first in your source.

Like this:

class MyClass(object): @classmethod @print_function_name def get_dir(cls): return dir(cls) @staticmethod @print_function_name def get_a(): return 'a' 
Sign up to request clarification or add additional context in comments.

Comments

42

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' 

2 Comments

As a rule, classmethod and staticmethod apply a special kind of magic and have to be called last.
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
2

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' 

3 Comments

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.