Сборка отчёта: из данных в готовую таблицу

Отчёт — это финальный продукт автоматизации таблиц: данные на входе, аккуратная сводка на выходе. Соберём весь пайплайн целиком, от сырых строк до форматированного итога.
Суть: отчёт = читать → агрегировать → форматировать → выгрузить. Каждый шаг — отдельная функция, а форматирование строк делает вывод человекочитаемым.

Мы прошли все детали: чтение CSV, расчёты, openpyxl. Теперь соберём из них типовую задачу бизнеса — ежедневный отчёт о продажах. Пайплайн: получить сделки, посчитать выручку по менеджерам и итоги, отформатировать в таблицу и выгрузить. Логику расчёта и форматирования отчёта целиком можно собрать на stdlib — запустим в браузере.

Попробуй сам ▶

from collections import defaultdict

# ВХОД
sales = [
    ('Аня', 'ноутбук', 75000), ('Боря', 'мышь', 1200),
    ('Аня', 'монитор', 18000), ('Вика', 'ноутбук', 82000),
    ('Боря', 'клавиатура', 3500), ('Аня', 'мышь', 1200),
]

# ОБРАБОТКА: выручка и число сделок по менеджеру
stats = defaultdict(lambda: {'sum': 0, 'count': 0})
for manager, item, price in sales:
    stats[manager]['sum'] += price
    stats[manager]['count'] += 1

# ВЫХОД: форматированная таблица
print(f"{'Менеджер':10}{'Сделок':>8}{'Выручка':>12}{'Средний чек':>14}")
print('-' * 44)
for m in sorted(stats, key=lambda x: -stats[x]['sum']):
    s = stats[m]
    avg = s['sum'] / s['count']
    print(f"{m:10}{s['count']:>8}{s['sum']:>12,}{avg:>14,.0f}")

grand = sum(s['sum'] for s in stats.values())
print('-' * 44)
print(f"{'ИТОГО':10}{'':>8}{grand:>12,}")

Здесь видно, как форматирование строк делает отчёт читаемым: :>12, выравнивает число по правому краю в 12 позиций и ставит разделители тысяч, :>14,.0f делает то же с округлением до целого. Без этого колонки «поплыли» бы.

ПАЙПЛАЙН ОТЧЁТА

  [ЧИТАТЬ]      [АГРЕГИРОВАТЬ]    [ФОРМАТ]      [ВЫГРУЗИТЬ]
  sales.csv  -> сумма+счёт по  -> выровнять  -> report.xlsx
               менеджеру          колонки       + итог
                 |                                |
                 +-- средний чек                  +-- email

  Каждый блок -> своя функция.

В продакшене выгрузка идёт в Excel через openpyxl — с жирным заголовком и формулой итога. Эта часть недоступна в браузере, поэтому показана как врезка language-text.

from openpyxl import Workbook
from openpyxl.styles import Font

wb = Workbook(); ws = wb.active; ws.title = 'Продажи'
ws.append(['Менеджер', 'Сделок', 'Выручка'])
for cell in ws[1]:                 # жирный заголовок
    cell.font = Font(bold=True)

for m, s in report_rows:           # данные из расчёта выше
    ws.append([m, s['count'], s['sum']])

last = ws.max_row
ws.cell(last + 1, 1, 'ИТОГО')
ws.cell(last + 1, 3, f'=SUM(C2:C{last})')
wb.save('report.xlsx')

Хороший отчёт почти всегда содержит контекст, а не только итоговые числа. Добавьте в шапку дату и период, за который собраны данные, а в подвал — отметку «сформировано автоматически такого-то числа». Если в данных были пропущенные или отброшенные строки, упомяните их количество: получатель должен понимать, на каких данных построен вывод. Эти мелочи отличают отчёт, которому доверяют, от безликой таблицы, к которой возникают вопросы. Автоматизация здесь снова в плюсе: скрипт проставит дату и пересчитает счётчики безошибочно, тогда как человек о такой «мелочи» легко забывает в спешке.

Как работает под капотом

Конструкция defaultdict(lambda: {'sum': 0, 'count': 0}) для каждого нового менеджера создаёт свежий словарь со счётчиками. Это удобный приём, когда на каждый ключ нужно агрегировать сразу несколько величин. Лямбда здесь — фабрика значения по умолчанию, она вызывается при первом обращении к новому ключу.

В мини-языке форматирования {value:>12,.0f} каждая часть значима: > — выравнивание вправо, 12 — ширина поля, запятая — разделитель тысяч, .0f — ноль знаков после точки. Освоив этот синтаксис, вы строите ровные таблицы без сторонних библиотек.

Частые ошибки

  • Считать и форматировать в одном месте. Расчёт и оформление — разные ответственности; смешав их, вы не сможете переиспользовать расчёт.
  • Делить на ноль в среднем чеке. Если у менеджера ноль сделок, расчёт упадёт. Проверяйте делитель.
  • Хардкодить диапазон формулы. Считайте границу через max_row, а не вписывайте число руками.

Best practices

  • Стройте отчёт по шагам пайплайна, каждый — отдельной функцией.
  • Сначала проверьте расчёт в консоли (как в браузерной врезке), потом подключайте выгрузку в Excel.
  • Добавляйте строку ИТОГО и метку даты — это то, что от отчёта ждёт человек.

Итоги. Отчёт — это собранный воедино пайплайн: чтение, агрегация, форматирование, выгрузка. Форматирование строк и defaultdict-агрегаты — ваши главные инструменты. Раздел о таблицах закрыт — переходим к текстам, PDF и Word.

Проверьте себя
1. Что делает спецификатор формата {x:>12,} в f-строке?
AОкругляет до 12 знаков
BВыравнивает вправо в поле шириной 12 и ставит разделители тысяч
CБерёт первые 12 символов
DДелит число на 12
2. Зачем в отчёте границу формулы SUM считать через ws.max_row?
AЧтобы формула работала быстрее
BЧтобы диапазон автоматически охватывал все строки данных, без хардкода
CЭто обязательное требование openpyxl
DЧтобы заголовок стал жирным