Python

Декораторы

Python

Классы-декораторы в Python

Основные концепции

1. Базовый класс-декоратор


class SimpleDecorator:
    def __init__(self, func):
        self.func = func  # Сохраняем декорируемую функцию

    def __call__(self, *args, **kwargs):
        print("Действие перед вызовом функции")
        result = self.func(*args, **kwargs)
        print("Действие после вызова функции")
        return result

@SimpleDecorator
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

2. Декоратор с параметрами


class ParametrizedDecorator:
    def __init__(self, prefix=""):
        self.prefix = prefix  # Параметр декоратора

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print(f"{self.prefix} Перед вызовом")
            result = func(*args, **kwargs)
            print(f"{self.prefix} После вызова")
            return result
        return wrapper

@ParametrizedDecorator(prefix="DEBUG:")
def calculate(a, b):
    return a + b

print(calculate(2, 3))

3. Сохранение метаданных функции


import functools

class MetadataPreservingDecorator:
    def __init__(self, func):
        self.func = func
        functools.wraps(func)(self)  # Сохраняем метаданные

    def __call__(self, *args, **kwargs):
        """Документация декоратора"""
        print("Дополнительная логика")
        return self.func(*args, **kwargs)

@MetadataPreservingDecorator
def example():
    """Оригинальная документация"""
    print("Функция выполнена")

print(example.__name__)  # example
print(example.__doc__)   # Оригинальная документация

Продвинутые техники

4. Декоратор методов класса


class MethodDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, instance, *args, **kwargs):
        print(f"Вызов метода {self.func.__name__} класса {instance.__class__.__name__}")
        return self.func(instance, *args, **kwargs)

class MyClass:
    @MethodDecorator
    def my_method(self):
        print("Метод выполнен")

obj = MyClass()
obj.my_method()

5. Декоратор с состоянием


class CounterDecorator:
    def __init__(self, func):
        self.func = func
        self.calls = 0

    def __call__(self, *args, **kwargs):
        self.calls += 1
        print(f"Функция вызвана {self.calls} раз")
        return self.func(*args, **kwargs)

@CounterDecorator
def say_hello():
    print("Hello!")

say_hello()
say_hello()

6. Декоратор с возможностью отключения


class SwitchableDecorator:
    def __init__(self, active=True):
        self.active = active

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            if self.active:
                print("Декоратор активен")
            return func(*args, **kwargs)
        return wrapper

@SwitchableDecorator(active=False)
def function():
    print("Функция выполнена")

function()

Важные моменты для собеседования

  1. Как работает декоратор?
    • Декоратор - это функция или класс, который принимает функцию и возвращает новую функцию
    • Синтаксис @decorator эквивалентен func = decorator(func)
  2. Разница между функцией-декоратором и классом-декоратором
    • Классы-декораторы полезны, когда нужно:
      • Сохранять состояние между вызовами
      • Реализовать сложную логику
      • Использовать ООП подход
  3. Почему functools.wraps важен?
    • Сохраняет оригинальное имя функции и документацию
    • Без него декорированная функция теряет свои метаданные
  4. Когда использовать классы-декораторы?
    • Когда нужен декоратор с состоянием
    • Для сложных декораторов с несколькими уровнями вложенности
    • Когда требуется повторно используемая логика декорирования

0
...

Асинхронный парсер

Python

Не так давно для одного небольшого проекта возникла необходимость пропарсить большое количество страниц, получить необходимую информацию и выгрузить изображения. Как раз в таких ситуациях, где быстро необходимо получить информацию из разных источников приходит на помощь асинхронность. В Python это реализуется очень просто.

...

Flask SQLAlchemy: Разбивка на страницы

Python

Если вы используете Flask SQLAlchemy, то у вас есть замечательная возможность делать пагинацию - разбивку на страницы для удобной навигации между записями. Делается это очень просто, буквально в несколько строк кода. Я расскажу как это реализовано в моем блоге в упрощенном виде, с использованием двух ссылок и вариант с нумерацией страниц.

...

Установка пакетов Python без подключения к интернету

Python

Иногда необходимо установить пакеты Python на устройство без доступа к интернету, например, в закрытых средах. В этом случае нужно предварительно скачать необходимые пакеты на устройство с подключением к сети, а затем установить их офлайн. Этот метод позволяет установить все необходимые зависимости, скачанные предварительно на устройство с подключением к интернету.

...

AJAX + FLASK

Python

Иногда необходимо выполнить определенные действия без обновления страницы - авторизоваться на сайте или поставить лайк. AJAX позволяет выполнить эти действия без особых проблем. В этой небольшой статье я расскажу как можно выполнить авторизацию на сайте без обновления страницы во Flask.

...