Декораторы в Python. Декоратор класса, декорирование методов в классе

При изучении декораторов, столкнулся с такой проблемой. Писал декоратор, который должен оборачивать все методы класса другим декоратором. Получилось следующее:

def log_method(time_format: str, cls_name: str) -> Callable:
""" Декоратор. Выводит имена класса, метода, время запуска и время его работы."""

    def method_decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapped_func(*args, **kwargs):
            formatted_time = ''.join('%' + sbl if sbl.isalpha() else sbl for sbl in time_format)
            print('- Запускается {}.{}. Дата и время запуска: {}'
                  .format(cls_name, func.__name__, datetime.now().strftime(formatted_time)))
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            print('- Завершение {}.{}, время работы = {}s'
                  .format(cls_name, func.__name__, round(end - start, 3)))
            return result
        return wrapped_func
    return method_decorator

Декоратор, который оборачивает методы класса:

def log_methods(time_format: str) -> Callable:
""" Декоратор. Применяет декоратор log_method ко всем методам класса. """

    def wrapped(cls):
        for i_method in dir(cls):
            if i_method.endswith('__') is False:
                method = getattr(cls, i_method)
                if callable(method):
                    decorated_method = log_method(time_format, cls.__name__)(method)
                    setattr(cls, i_method, decorated_method)
        return cls
     return wrapped

Тестовый класс:

@log_methods("b d Y - H:M:S")
class ExampleClass:
    def sum_1(self) -> int:
        print("sum 1")
        number = 100
        result = 0
        for _ in range(number + 1):
            result += sum([i_num ** 2 for i_num in range(10000)])
        return result

    def sum_2(self):
        print("sum 2")
        number = 200
        result = 0
        for _ in range(number + 1):
            result += sum([i_num ** 2 for i_num in range(10000)])
        return result

Пока все работает. И запуск команд:

my_obj = ExampleClass()
my_obj.sum_1()
my_obj.sum_2()

Выдает:

- Запускается ExampleClass.sum_1. Дата и время запуска: Jun 18 2021 - 15:18:41
sum 1
- Завершение ExampleClass.sum_1, время работы = 0.271s
- Запускается ExampleClass.sum_2. Дата и время запуска: Jun 18 2021 - 15:18:41
sum 2
- Завершение ExampleClass.sum_2, время работы = 0.52s

Process finished with exit code 0

Но, если я оберну метод в классе через @classmethod (что логично для приведенного класса).

    ...
    @classmethod
    def sum_1(cls) -> int:
        print("sum 1")
        number = 100
        result = 0
        for _ in range(number + 1):
            result += sum([i_num ** 2 for i_num in range(10000)])
        return result
    ...

Я получу ошибку:

Traceback (most recent call last):
  File "E:\Projects\LearningPython\example_14.py", line 63, in <module>
    my_obj.sum_1()
  File "E:\Projects\LearningPython\example_14.py", line 17, in wrapped_func
    result = func(*args, **kwargs)
TypeError: sum_1() takes 1 positional argument but 2 were given

Моих знаний и понимания не хватает, чтобы исправить эту ошибку. Почему теперь в метод sum_1 передаются два аргумента (видимо из-за декоратора classmethod, так и не нашел что он конкретно делает и возвращает)? А, главное, как это исправить?

Код целиком: https://pastebin.com/8BmX69vi

Спасибо!


Ответы (0 шт):