Не работает декоратор метода класса

Рейтинг: 0Ответов: 1Опубликовано: 27.04.2023

Пока я использую декоратор без @, всё вызывается и работает, но когда я пытаюсь вызвать декоратор через @, декоратор не находит декорируемую функцию. Использовать декоратор без "собачки" можно, но неудобно. Подскажите, пожалуйста, в чем здесь дело? Заранее благодарен!

import time


class Cls:
    def __init__(self, file_name):
        print(f'constructor -> "{file_name}"')  # .....

    def chronometer(self, func):  # Метод-Декоратор
        def wrapper(*args, **kwargs):
            print(f'{func.__name__} - started')
            func(*args, **kwargs)
            print(f'{func.__name__} - finished')

        return wrapper

    @chronometer                    # (Не могу ПРИДЕЛАТЬ декоратор через собачку-@)
    def decorated_fun(self):  # декорируемый Метод
        for i in range(5):
            print(f'  ***** ({i})')  # .....
            time.sleep(0.2)

    def apply(self):  # Метод применения Декоратора
        # --------------------------------------------------------------------------
        # # Вариант 1: - (без собачки-@)  # (РАБОТАЕТ!)
        # self.chronometer(self.decorated_fun)()
        # --------------------------------------------------------------------------
        # # Вариант 2: - (без собачки-@)  # (РАБОТАЕТ!)
        # self.decorated_fun = self.chronometer(self.decorated_fun)
        # self.decorated_fun()
        # --------------------------------------------------------------------------
        # Вариант 3: - (с собачкой-@)  # (НЕ РАБОТАЕТ!)
        self.decorated_fun()
        # --------------------------------------------------------------------------
        pass


# обращение:
cls = Cls('aquarius.dat')
cls.apply()

# Вывод:
# constructor -> "aquarius.dat"
# decorated - started
#   ***** (0)
#   ***** (1)
#   ***** (2)
#   ***** (3)
#   ***** (4)
# decorated - finished

Ответы

▲ 4Принят

Нужно переделать декоратор, self убрать во wrapper:

    def chronometer(func):  # Метод-Декоратор
        def wrapper(self, *args, **kwargs):
            print(f'{func.__name__} - started')
            func(self, *args, **kwargs)
            print(f'{func.__name__} - finished')
        return wrapper

Рецепт подсмотрен на английском СО.

Но вообще так лучше не делать, как написано там же. Декораторы лучше не помещать в классы.