Пример ответа
1) Короткий ответ
Декоратор в Python — это функция, которая принимает другую функцию и расширяет её поведение, не изменяя исходный код. Это паттерн для добавления функциональности "обёртки".
2) Как работает (3 ключевые идеи + пример):
1. Базовый принцип: Декоратор принимает функцию-цель, добавляет логику до/после вызова и возвращает новую функцию-обёртку.
2. Синтаксис: Используется символ @
для применения декоратора к функции.
3. Применение: Кэширование, логирование, проверка прав доступа, тайминг, повторные попытки.
Пример создания и использования:
```python
# Декоратор для логирования
def logger(func):
def wrapper(*args, **kwargs):
print(f"Вызов функции {func.__name__} с аргументами {args}")
result = func(*args, **kwargs)
print(f"Функция {func.__name__} завершилась")
return result
return wrapper
# Применение декоратора
@logger
def calculate_sum(a, b):
return a + b
# Вызов функции
result = calculate_sum(5, 3)
# Вывод:
# Вызов функции calculate_sum с аргументами (5, 3)
# Функция calculate_sum завершилась
```
4) Сравнение с альтернативами:
* Декораторы:
* Плюсы: Чистый код, повторное использование, разделение ответственности
* Минусы: Сложность отладки, накладные расходы
* Явный вызов функций:
* Плюсы: Простота, прозрачность
* Минусы: Дублирование кода, нарушение DRY
Рекомендация: Используйте декораторы для cross-cutting concerns (логирование, кэширование, аутентификация), но избегайте избыточного вложения.
5) Практический пример для Data Engineer:
```python
from functools import wraps
import time
# Декоратор для измерения времени выполнения
def timing(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"Время выполнения {func.__name__}: {end - start:.2f} сек")
return result
return wrapper
# Применение к ETL-функции
@timing
def process_data(file_path):
# Имитация обработки данных
df = spark.read.csv(file_path)
processed_df = df.filter("value > 0")
return processed_df.count()
# Использование
record_count = process_data("data.csv")
```
6) Follow-up вопросы:
* Зачем нужен @wraps из functools?
* Ответ: Сохраняет метаданные оригинальной функции (имя, docstring)
* Можно ли создать декоратор с параметрами?
* Ответ: Да, через вложенные функции
7) Практический совет (2 шага на неделю):
1. Напишите полезный декоратор: Создайте декоратор для повторных попыток (retry), который будет перезапускать функцию при возникновении исключений.
2. Проанализируйте готовые декораторы: Изучите исходный код @lru_cache
из functools чтобы понять реализацию кэширования.