Мышление пайплайнами: вход — обработка — выход
Любой скрипт автоматизации — это конвейер: данные входят, проходят через цепочку преобразований и выходят в новом виде. Спроектируйте конвейер — и код напишется сам.
Суть: разбейте задачу на функции «прочитать», «обработать», «записать». Каждая делает одно дело, и их легко тестировать и переставлять.
Новички часто пишут автоматизацию одной длинной простынёй кода: тут читаем файл, тут же считаем, тут же отправляем письмо. Такой код невозможно ни понять, ни починить. Профессионал сначала рисует поток данных, а потом превращает каждую стрелку в функцию.
Возьмём типичную задачу: из списка продаж посчитать выручку по менеджерам и отдать отчёт. Поток выглядит так.
ПОТОК ОБРАБОТКИ ДАННЫХ
read_sales() обработка write_report()
---------- ---------------- --------------
список -> группируем по -> строки отчёта
сделок менеджеру, сумма готовый текст
|
+-> validate() отсеять брак
каждая функция = один блок схемыКогда поток нарисован, код становится почти механическим переводом схемы. Вот рабочий пример на чистом stdlib — он группирует сделки и считает выручку с помощью collections.
Попробуй сам ▶
from collections import defaultdict
# ВХОД: список сделок (менеджер, сумма)
sales = [
('Аня', 1200), ('Боря', 800), ('Аня', 1500),
('Вика', 2000), ('Боря', 1100), ('Аня', 300),
]
# ОБРАБОТКА: группируем по менеджеру
revenue = defaultdict(int)
for manager, amount in sales:
revenue[manager] += amount
# ВЫХОД: отчёт, отсортированный по убыванию
print('Выручка по менеджерам:')
for manager, total in sorted(revenue.items(), key=lambda x: -x[1]):
print(f' {manager:6} {total:>6} руб')
print(f' ИТОГО {sum(revenue.values()):>6} руб')Обратите внимание: три комментария-блока (вход / обработка / выход) повторяют схему. Это не случайно — хорошо спроектированный код читается как диаграмма.
Пайплайн-мышление окупается и при отладке. Когда скрипт выдаёт неверный результат, монолитный код приходится перечитывать целиком, гадая, где ошибка. А разбитый на блоки пайплайн отлаживается по шагам: распечатали результат чтения — верно; распечатали результат обработки — вот здесь поехало. Вы локализуете проблему за минуты, а не за час. Тот же принцип помогает и расширять скрипт: новое требование почти всегда ложится в один из блоков, не задевая остальные. Это и есть инженерная зрелость — код, который не страшно менять.
Как работает под капотом
defaultdict(int) — это словарь, который для отсутствующего ключа сам создаёт значение по умолчанию (здесь 0). Поэтому revenue[manager] += amount работает даже при первой встрече менеджера: не нужно вручную проверять, есть ли ключ. Это классический приём группировки.
Функция sorted с параметром key сортирует не сами элементы, а результат функции от них. key=lambda x: -x[1] сортирует по сумме (второй элемент пары) в обратном порядке — минус превращает возрастание в убывание.
Частые ошибки
- Смешивать чтение, расчёт и вывод в одной функции. Тогда нельзя протестировать расчёт, не трогая файлы.
- Не валидировать вход. Битая строка в данных уронит весь скрипт. Отсеивайте брак на входе.
- Жёстко зашивать пути и параметры в середину логики. Выносите их наверх, в начало скрипта.
Best practices
- Одна функция — одна ответственность: читать, обрабатывать или писать.
- Передавайте данные между функциями, а не глобальные переменные.
- Сначала схема потока на бумаге, потом код. Так короче и надёжнее.
Итоги. Пайплайн-мышление — главный навык автоматизатора. Разделяйте чтение, обработку и запись на отдельные функции, проектируйте поток данных заранее, валидируйте вход. Теперь, когда фундамент заложен, перейдём к первому реальному источнику данных — файлам и папкам.