Подтвердить что ты не робот

Почему @decorator не может украсить staticmethod или classmethod?

Почему decorator не может украсить статический метод или метод класса?

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'

И get_dir и get_a приводят к AttributeError: <'classmethod' or 'staticmethod'>, object has no attribute '__name__'.

Почему decorator полагается на атрибут __name__ вместо атрибута func_name? (Во всех функциях, включая методы классов и статические методы, есть атрибут func_name.)

Редактировать: я использую Python 2.6.

4b9b3361

Ответ 1

Это работает, когда @classmethod и @staticmethod - самые лучшие декораторы:

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

classmethod и staticmethod возвращают объекты дескриптора, а не функции. Большинство декораторов не предназначены для приема дескрипторов.

Как правило, тогда вы должны применять classmethod и staticmethod последними при использовании нескольких декораторов. А поскольку декораторы применяются в порядке "снизу вверх", classmethod и staticmethod обычно должен быть самым верхним в вашем источнике.

Как это:

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

Это то, что вы хотели?

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'