Streamlit на Python: от основ до проекта

Курс обучает созданию интерактивных веб-приложений на Streamlit с нуля до полноценного проекта. Включает теорию, мини-тесты, практические задачи и поэтапную разработку итогового приложения на основе изученного материала.

1. Введение в Streamlit: установка, запуск, структура приложения

Введение в Streamlit: установка, запуск, структура приложения

Streamlit — это библиотека на Python для быстрого создания интерактивных веб-приложений для аналитики данных, прототипирования и внутренних инструментов. Главная идея: вы пишете обычный Python-скрипт, а Streamlit превращает его в веб-интерфейс.

В этой статье вы:

  • установите Streamlit в отдельное окружение
  • запустите первое приложение
  • поймёте базовую структуру проекта и то, как Streamlit исполняет код
  • Что такое Streamlit и как он работает

    Streamlit запускает ваш Python-скрипт как приложение и отображает результат в браузере. Почти всё, что вы выводите через st.* (например, st.write, st.title, st.dataframe), становится частью интерфейса.

    Ключевое поведение Streamlit:

  • Скрипт выполняется сверху вниз.
  • При любом взаимодействии пользователя (нажатие кнопки, изменение слайдера, ввод текста) Streamlit обычно делает перезапуск скрипта.
  • Состояние виджетов (их текущие значения) Streamlit хранит отдельно и подставляет их при перезапуске.
  • !Упрощённая схема того, как Streamlit выполняет скрипт и перезапускает его при действиях пользователя

    Подготовка окружения

    Рекомендуется ставить Streamlit в виртуальное окружение, чтобы зависимости курса не конфликтовали с другими проектами.

    Вариант A: venv (стандартный способ в Python)

  • Создайте папку проекта, например streamlit-course.
  • Создайте виртуальное окружение.
  • Активируйте его.
  • Установите Streamlit.
  • Команды:

    Полезные ссылки:

  • Документация Python: venv
  • Документация pip: Installation
  • Вариант B: conda (если вы уже работаете через Anaconda/Miniconda)

    Ссылка:

  • Документация conda: Managing environments
  • Первый запуск Streamlit

    Создайте файл app.py в папке проекта:

    Запустите приложение:

    После запуска Streamlit обычно:

  • выводит локальный адрес (часто http://localhost:8501)
  • автоматически открывает браузер (если не отключено настройками)
  • Остановить приложение можно сочетанием клавиш Ctrl+C в терминале.

    Официальное руководство по старту:

  • Streamlit docs: Get started
  • Минимальная структура приложения

    На старте достаточно одного файла app.py. Но уже на раннем этапе удобно иметь структуру проекта.

    Пример рекомендуемой структуры для курса:

    Пояснения:

  • .venv/ — виртуальное окружение (обычно не коммитят в git)
  • app.py — основной файл приложения
  • requirements.txt — список зависимостей
  • README.md — описание проекта и как его запускать
  • Чтобы сохранить зависимости:

    Основные элементы интерфейса в Streamlit

    Streamlit предоставляет функции st.*, которые добавляют элементы на страницу. Ниже — базовый набор, который пригодится уже в первых уроках.

    Текст и заголовки

    Важно понимать различия:

  • st.title, st.header, st.subheader — для структуры страницы
  • st.write — самый универсальный способ что-то показать
  • Отображение данных

    st.dataframe удобен для интерактивного просмотра таблиц (прокрутка, масштабирование колонок).

    Виджеты (элементы управления)

    Виджеты возвращают значение — и это ключ к интерактивности.

    Что происходит при изменении слайдера:

  • пользователь двигает слайдер
  • Streamlit перезапускает скрипт
  • age получает новое значение
  • интерфейс перерисовывается
  • Как Streamlit исполняет код: важные правила

    Эти правила объясняют многие неожиданные эффекты у новичков.

    Скрипт выполняется сверху вниз

    Если в коде сначала создаётся таблица, а потом отображается — всё будет нормально. Но если вы ожидаете, что «кусок кода выполнится только после нажатия кнопки», нужно явно использовать логику с условием.

    Пример:

    Перезапуск — это норма

    Почти любое действие пользователя приводит к перезапуску скрипта. Поэтому:

  • нельзя полагаться на «сохранение» значений в обычных переменных между перезапусками
  • для долговременного состояния позже понадобится st.session_state (в следующих темах)
  • для тяжёлых вычислений позже пригодятся кэширование и оптимизации (тоже будет в курсе)
  • Ошибки и логи

    Если приложение не запускается или падает:

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

  • У вас установлен Python и создано отдельное окружение (venv или conda).
  • В окружении установлен streamlit.
  • Вы умеете запускать приложение командой streamlit run app.py.
  • Вы понимаете, что скрипт выполняется сверху вниз и перезапускается при действиях пользователя.
  • В следующей статье курса мы будем разбирать базовые компоненты интерфейса Streamlit глубже и начнём собирать каркас будущего проекта.

    2. Виджеты и ввод данных: формы, кнопки, состояния

    Виджеты и ввод данных: формы, кнопки, состояния

    В прошлой статье вы запустили первое приложение и узнали два ключевых правила Streamlit: код выполняется сверху вниз и обычно перезапускается при любом действии пользователя. Теперь разберём, как строить управляемый ввод: виджеты, формы и сохранение состояния, чтобы приложение вело себя предсказуемо.

    Что такое виджеты в Streamlit

    Виджет — это элемент интерфейса, с которым пользователь взаимодействует (вводит текст, выбирает вариант, нажимает кнопку). В Streamlit любой виджет:

  • рисуется вызовом st.* (например, st.text_input)
  • возвращает значение (например, строку или число)
  • хранит своё текущее значение между перезапусками приложения
  • Простейший пример:

    Когда пользователь вводит текст, скрипт перезапускается, но Streamlit подставляет текущее значение виджета обратно в переменную name.

    Часто используемые виджеты ввода

    Ниже — набор виджетов, которых достаточно для большинства учебных и рабочих приложений.

    Текст, числа и выбор

    Флажки и множественный выбор

    Дата и загрузка файла

    Официальный справочник виджетов:

  • Streamlit API reference: Widgets
  • Кнопки: как они работают и почему “срабатывают один раз”

    st.button возвращает True только на том перезапуске, который был вызван нажатием кнопки. На следующем перезапуске (например, после изменения другого виджета) значение снова будет False.

    Это поведение удобно для действий в момент клика: отправить форму, запустить расчёт, добавить строку в список.

    Обработчики on_click

    У многих виджетов есть параметры on_click и args/kwargs: вы передаёте функцию, которая будет вызвана при событии.

    На практике вы часто будете комбинировать on_click и st.session_state, чтобы отделить событие (клик) от состояния (данные, которые должны жить дольше одного перезапуска).

    Справочник по кнопке:

  • Streamlit API reference: st.button
  • Ключи key: зачем они нужны

    Streamlit идентифицирует виджеты. Обычно он справляется сам, но в реальных приложениях важно управлять идентификацией явно.

    Используйте key, когда:

  • у вас два одинаковых виджета с одинаковыми подписями
  • виджет создаётся в цикле
  • вы хотите обращаться к значению через st.session_state["..."]
  • Пример: два поля с одинаковой подписью без key вызовут ошибку.

    Состояние приложения: st.session_state

    Поскольку скрипт перезапускается постоянно, обычные переменные не подходят для хранения данных “между кликами”. Для этого в Streamlit есть сессионное состояниеst.session_state.

    Сессия — это текущий пользователь и его вкладка браузера. У каждого пользователя своё st.session_state.

    Инициализация состояния

    Хорошая привычка — задавать значения по умолчанию один раз:

    Счётчик кликов

    Здесь counter сохраняется между перезапусками и меняется только по клику.

    Документация по состоянию:

  • Streamlit API reference: st.session_state
  • Формы: как не перезапускать скрипт на каждый символ

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

  • заполнить несколько полей
  • нажать одну кнопку Отправить
  • обработать всё сразу
  • Для этого используйте st.form.

    !Схема показывает разницу между обычными виджетами и формой: форма отправляет данные одним действием

    Пример формы

    Важные правила форм:

  • все виджеты, которые должны “отправляться вместе”, размещайте внутри with st.form(...)
  • кнопку отправки делайте через st.form_submit_button
  • данные формы удобно сохранять в st.session_state, если вы хотите накапливать их
  • Документация по формам:

  • Streamlit API reference: st.form
  • Практический шаблон для мини-проекта: “добавить записи и показать таблицу”

    Этот шаблон пригодится дальше в курсе, когда вы будете собирать проект: пользователь вводит данные, вы добавляете их в список в st.session_state, и отображаете результат.

    Что здесь важно для будущего проекта:

  • форма собирает значения и отправляет их одной кнопкой
  • данные живут в st.session_state и не пропадают при перезапуске
  • таблица строится из накопленных записей
  • Типичные ошибки новичков и как их избежать

  • Ожидать, что переменная “сохранится” между кликами: используйте st.session_state для долгоживущих данных.
  • Получить конфликт виджетов: задавайте key, особенно в циклах и при одинаковых подписях.
  • Случайно запускать обработку на каждый ввод: оборачивайте анкетные сценарии в st.form.
  • Пытаться “держать логику” в кнопке без состояния: кнопка — это событие на один перезапуск, а данные должны храниться отдельно.
  • Мини-чеклист перед следующей темой

  • Вы умеете использовать базовые виджеты и получать их значения.
  • Вы понимаете, что st.button возвращает True только в момент клика.
  • Вы применяете key, когда виджетов много или они динамические.
  • Вы храните долгоживущие данные в st.session_state.
  • Вы используете st.form, чтобы отправлять набор полей одной кнопкой.
  • 3. Отображение данных: таблицы, графики, медиа и разметка

    Отображение данных: таблицы, графики, медиа и разметка

    В предыдущих статьях вы разобрались, как Streamlit запускает приложение (выполнение сверху вниз и перезапуски) и как собирать ввод пользователя через виджеты, формы и st.session_state. Следующий шаг к проекту — научиться правильно показывать результат: таблицы, графики, изображения, видео и аккуратную разметку страницы.

    Цель этой темы — чтобы вы могли собрать понятный интерфейс: пользователь вводит данные, а приложение отображает их в удобном виде и помогает быстро сделать вывод.

    Универсальный вывод и текстовая разметка

    st.write как базовый способ показать почти всё

    st.write — универсальная функция вывода. Она умеет отображать строки, числа, списки, словари, таблицы, датафреймы и даже некоторые типы графиков.

    Документация:

  • st.write
  • st.markdown для форматирования текста

    Когда нужно управлять форматированием (списки, ссылки, выделение), используйте st.markdown. Это удобно для описаний, инструкций, комментариев к графикам.

    Документация:

  • st.markdown
  • Полезные элементы текста

  • st.caption — короткая подпись под блоком
  • st.code — показать фрагмент кода
  • st.json — красиво отрендерить словарь или JSON-подобную структуру
  • Таблицы: st.dataframe и st.table

    В реальных приложениях таблицы — один из главных способов показать данные.

    Чем отличаются st.dataframe и st.table

    | Компонент | Когда использовать | Особенности | |---|---|---| | st.dataframe | аналитика и просмотр данных | интерактивность: прокрутка, изменение ширины, удобная навигация | | st.table | небольшие итоговые сводки | статическая таблица без интерактивности |

    Пример:

    Документация:

  • st.dataframe
  • st.table
  • Практический паттерн: фильтр плюс таблица

    Здесь вы используете виджеты из прошлой темы, а таблицу — из текущей.

    Графики: быстрые и гибкие

    Графики обычно строятся из таблиц, поэтому чаще всего вы начинаете с pandas.DataFrame, а затем выбираете уровень контроля.

    !Схема показывает, что графики строятся из табличных данных и какие есть уровни контроля

    Быстрые графики Streamlit: st.line_chart, st.bar_chart, st.area_chart

    Это самый быстрый путь к визуализации, когда вам не нужна тонкая настройка.

    Документация:

  • st.line_chart
  • st.bar_chart
  • st.area_chart
  • Более гибко: Altair и st.altair_chart

    Altair удобен, когда вам важны подписи осей, интерактивные подсказки, цвета, группировки.

    Документация:

  • st.altair_chart
  • Установка, если нужно:

    Интерактивные дашборд-графики: Plotly и st.plotly_chart

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

    Документация:

  • st.plotly_chart
  • Установка, если нужно:

    Медиа: изображения, аудио, видео

    Медиа часто используется в прикладных проектах: отчёты, демонстрации моделей, внутренние инструменты.

    Изображения: st.image

    Можно показывать изображение из файла, по URL или из загруженного пользователем файла.

    Документация:

  • st.image
  • st.file_uploader
  • Аудио и видео: st.audio, st.video

    Документация:

  • st.audio
  • st.video
  • Компоновка страницы: колонки, вкладки, сайдбар

    Когда данных становится много, важно не только что показывать, но и как расположить это на странице.

    Колонки: st.columns

    Типичный сценарий: слева фильтры или метрики, справа таблица или график.

    Документация:

  • st.columns
  • Вкладки: st.tabs

    Удобно разделять большие разделы: Таблица, График, Описание.

    Документация:

  • st.tabs
  • Сайдбар: st.sidebar

    Сайдбар обычно используют для фильтров, настроек и навигации. Это помогает оставить основную область для результатов.

    Документация:

  • st.sidebar
  • Связь с будущим проектом: превращаем ввод в понятный отчёт

    Из прошлой темы у вас уже есть паттерн форма добавляет записи в st.session_state. Теперь добавим отображение результата: таблицу, сводку и простой график.

    Здесь важны две идеи:

  • интерфейс управляется виджетами и формами, а результат показывается таблицами, метриками и графиками
  • данные не пропадают при перезапусках, потому что хранятся в st.session_state
  • Мини-чеклист перед следующей темой

  • Вы различаете st.dataframe и st.table и выбираете подходящий вариант.
  • Вы умеете строить быстрые графики (st.line_chart, st.bar_chart) и понимаете, когда нужен Altair или Plotly.
  • Вы можете показать медиа через st.image, st.audio, st.video.
  • Вы умеете структурировать страницу с помощью st.columns, st.tabs и переносить настройки в st.sidebar.
  • 4. Работа с данными: загрузка файлов, API, pandas и обработка

    Работа с данными: загрузка файлов, API, pandas и обработка

    В прошлых темах вы научились строить интерфейс (виджеты, формы, st.session_state) и красиво показывать результат (таблицы, графики, разметка). Теперь соберём сердце большинства приложений: работу с данными.

    В этой статье вы разберёте:

  • как загружать файлы от пользователя и превращать их в pandas.DataFrame
  • как получать данные из API и превращать JSON в таблицы
  • как обрабатывать данные в pandas так, чтобы это хорошо работало с перезапусками Streamlit
  • как ускорять приложение кэшированием
  • !Общая картина: откуда берутся данные и как они превращаются в таблицы и графики

    Как Streamlit влияет на работу с данными

    Streamlit перезапускает скрипт при действиях пользователя, поэтому важно разделять:

  • состояние пользователя: выбранные фильтры, добавленные записи, шаги интерфейса (обычно st.session_state)
  • данные и вычисления: загрузка файла, запрос к API, тяжёлые преобразования (часто кэшируют)
  • Практическое правило:

  • храните в st.session_state то, что пользователь меняет руками и ожидает видеть сохранённым (например, список добавленных задач)
  • кэшируйте то, что дорого получать или вычислять, но легко пересчитать при необходимости (например, загрузку CSV или запрос к API)
  • Документация:

  • Streamlit: Session State
  • Streamlit: st.cache_data
  • Загрузка файлов от пользователя

    Самый частый сценарий для учебных проектов: пользователь приносит CSV/Excel, а приложение строит отчёт.

    st.file_uploader: что он возвращает

    st.file_uploader возвращает:

  • None, если файл не выбран
  • объект загруженного файла, похожий на файловый поток, который можно читать
  • Документация:

  • Streamlit: st.file_uploader
  • Загрузка CSV в pandas

    pandas умеет читать CSV из файлового объекта, поэтому код получается простым.

    Ссылки:

  • pandas: read_csv
  • Загрузка Excel

    Excel-файлы читаются через pd.read_excel. Обычно потребуется движок openpyxl.

    Ссылки:

  • pandas: read_excel
  • openpyxl (пакет)
  • Выгрузка результата пользователю: st.download_button

    Часто нужно дать пользователю скачать обработанную таблицу.

    Документация:

  • Streamlit: st.download_button
  • Получение данных из API

    API обычно отдаёт данные по HTTP в формате JSON. Типовой поток такой:

  • вы делаете HTTP-запрос
  • проверяете статус ответа
  • парсите JSON
  • нормализуете структуру и превращаете в таблицу
  • Для запросов обычно используют requests.

    Ссылки:

  • requests: Quickstart
  • Базовый пример: GET-запрос и таблица

    Ниже пример с публичным тестовым API.

    Почему здесь важен timeout:

  • без таймаута приложение может долго "висеть" при проблемах сети
  • в интерактивном интерфейсе лучше падать быстро и показывать понятную ошибку
  • Преобразование вложенного JSON: pd.json_normalize

    Если API возвращает вложенные объекты, удобно использовать json_normalize.

    Ссылка:

  • pandas: json_normalize
  • Где хранить API-ключи: st.secrets

    Если API требует ключ, не вставляйте его в код и не коммитьте в репозиторий. В Streamlit принято использовать st.secrets.

    Ссылка:

  • Streamlit: Secrets management
  • Идея использования выглядит так:

    Обработка данных в pandas: минимальный набор для проекта

    В проекте вам обычно нужно:

  • привести типы (числа, даты)
  • обработать пропуски
  • отфильтровать строки по условиям
  • посчитать агрегаты и построить таблицы/графики
  • Ссылки:

  • pandas: User Guide
  • Приведение типов и пропуски

    Практические замечания:

  • errors="coerce" превращает некорректные значения в NaN, чтобы вы могли их обработать
  • dropna(subset=[...]) удаляет строки, где пропуски критичны для анализа
  • Ссылки:

  • pandas: to_numeric
  • pandas: to_datetime
  • Фильтрация, группировка, агрегация

    Ссылки:

  • pandas: DataFrame.groupby
  • Полезный приём для Streamlit: держите обработку в функциях

    Так проще кэшировать и тестировать преобразования.

    Кэширование данных и вычислений: st.cache_data

    Если вы:

  • читаете большой CSV
  • ходите в API
  • делаете тяжёлую обработку
  • то без кэша приложение может стать медленным, потому что эти операции будут повторяться при каждом перезапуске.

    st.cache_data сохраняет результат функции и возвращает его повторно, если входные параметры те же.

    Важные правила кэша:

  • кэшируйте чистые функции, которые зависят только от входов
  • не прячьте внутрь кэшируемой функции чтение из st.session_state или случайность
  • если данные должны обновляться, кэшу можно задать время жизни (TTL)
  • Пример с TTL для API:

    Документация:

  • Streamlit: st.cache_data
  • Практический каркас для будущего проекта: "Импорт + очистка + отчёт"

    Ниже пример того, как объединить всё изученное в один понятный поток: пользователь загружает CSV, вы приводите типы, даёте фильтры, показываете таблицу и метрики.

    Этот каркас напрямую опирается на прошлые темы:

  • фильтры и управление параметрами через виджеты
  • вывод через st.dataframe, st.metric, st.bar_chart
  • ускорение через st.cache_data
  • Частые ошибки и как их диагностировать

  • Файл не читается: проверьте sep, encoding, и что файл действительно CSV.
  • Колонок нет: выводите st.write(df.columns) и проверяйте имена.
  • Числа стали строками: применяйте pd.to_numeric(..., errors="coerce").
  • Даты не парсятся: применяйте pd.to_datetime(..., errors="coerce") и проверяйте формат.
  • Приложение тормозит: вынесите загрузку и тяжёлую обработку в кэшируемые функции.
  • API периодически падает: используйте timeout, try/except, показывайте ошибку через st.error и st.exception.
  • Мини-чеклист перед следующими темами и проектом

  • Вы умеете читать CSV/Excel из st.file_uploader в pandas.DataFrame.
  • Вы умеете получать JSON из API через requests и превращать его в таблицу.
  • Вы применяете базовую очистку данных: типы, пропуски, фильтры, группировки.
  • Вы понимаете, что кэшировать через st.cache_data, а что хранить в st.session_state.
  • 5. Производительность и архитектура: кэш, Session State, компоненты

    Производительность и архитектура: кэш, Session State, компоненты

    Streamlit удобен тем, что вы пишете обычный Python-код, а интерфейс строится автоматически. Но у этого есть цена: при любом действии пользователя скрипт часто перезапускается целиком. Если приложение читает файлы, ходит в API или считает тяжёлые агрегации, без правильной архитектуры оно быстро станет медленным и неудобным.

    Эта тема связывает всё, что вы уже изучили:

  • вы умеете строить интерфейс на виджетах и формах
  • вы умеете отображать таблицы, графики и метрики
  • вы умеете загружать данные и обрабатывать их в pandas
  • Теперь вы научитесь делать это быстро и поддерживаемо:

  • правильно использовать st.session_state для пользовательского состояния
  • кэшировать загрузку/обработку через st.cache_data
  • кэшировать «ресурсы» (подключения, модели) через st.cache_resource
  • собирать приложение из компонентов (модулей и функций), чтобы было проще расширять проект
  • !Диаграмма показывает, как перезапуски Streamlit сочетаются с состоянием и кэшем

    Почему Streamlit “тормозит” и что с этим делать

    Причины медленной работы обычно типовые:

  • на каждом перезапуске вы заново читаете большой CSV или Excel
  • на каждом перезапуске вы снова делаете запрос к API
  • на каждом перезапуске вы повторяете одинаковую обработку pandas
  • вы создаёте тяжёлые объекты заново (подключение к БД, модель ML)
  • Правильная стратегия:

  • пользовательское состояние хранить в st.session_state
  • данные и вычисления кэшировать через st.cache_data
  • долгоживущие ресурсы кэшировать через st.cache_resource
  • Официальные ссылки:

  • st.session_state
  • st.cache_data
  • st.cache_resource
  • Session State как слой состояния приложения

    Что хранить в st.session_state

    st.session_state нужен для всего, что пользователь ожидает сохранить между перезапусками:

  • текущие значения виджетов по ключам key
  • результаты действий пользователя (добавленные записи, выбранные элементы)
  • “режимы” интерфейса (например, показывать ли расширенный отчёт)
  • Неудачная идея: складывать в st.session_state всё подряд, включая большие датафреймы, если их можно получить из кэша. На практике лучше держать в состоянии то, что не является чисто вычисляемым и зависит от действий пользователя.

    Паттерн: инициализация значений по умолчанию

    Дальше вы можете обновлять этот словарь из обработчиков или из формы.

    Паттерн: “событие” отдельно от “данных”

    Кнопка st.button даёт True только на перезапуске клика. Поэтому удобно делать так:

  • кнопка меняет состояние
  • интерфейс рисуется из состояния
  • Кэш данных: st.cache_data

    Что делает st.cache_data

    st.cache_data кэширует результат функции по её входным параметрам. Если функция вызывается снова с теми же аргументами, Streamlit возвращает сохранённый результат, а не пересчитывает.

    Используйте st.cache_data для:

  • чтения CSV/Excel
  • запросов к API
  • очистки/преобразования данных в pandas
  • вычисления агрегатов и сводок
  • Пример: кэшируем загрузку и очистку.

    TTL: кэш с “временем жизни”

    Если источник данных меняется (например, API), задайте ttl в секундах.

    Идея простая: в течение 60 секунд повторные вызовы будут быстрыми, а потом данные обновятся.

    Важное правило: кэшируйте чистые функции

    Функция хорошо кэшируется, если:

  • результат зависит только от входных аргументов
  • внутри нет скрытых зависимостей от глобального состояния и случайности
  • Плохие кандидаты на кэш:

  • функция читает st.session_state внутри себя
  • функция зависит от текущего времени без ttl
  • функция меняет внешний мир (пишет в файл, отправляет данные)
  • Кэш ресурсов: st.cache_resource

    st.cache_resource предназначен не для данных, а для тяжёлых объектов, которые создаются долго, но потом многократно используются:

  • подключение к базе данных
  • клиент внешнего сервиса
  • загруженная ML-модель
  • объект, который держит пул соединений
  • Пример: кэшируем создание “клиента” (упрощённо).

    Таблица выбора:

    | Задача | Что использовать | Что кэшируется | |---|---|---| | Прочитать CSV и вернуть DataFrame | st.cache_data | результат (данные) | | Сходить в API и вернуть JSON | st.cache_data | результат (данные) | | Держать подключение/клиент/модель | st.cache_resource | объект-ресурс | | Хранить действия пользователя | st.session_state | состояние сессии |

    Архитектура приложения: разделяем UI, данные и логику

    Когда приложение растёт, главный источник проблем не графики и не виджеты, а “всё в одном файле”. Хорошая учебная архитектура для проекта строится вокруг трёх слоёв:

  • UI слой: виджеты, табы, сайдбар, вывод
  • слой данных: загрузка, API, чтение файлов
  • бизнес-логика: очистка, фильтры, агрегаты
  • Минимальная структура проекта

    Роли модулей:

  • data.py содержит функции загрузки и получения данных (обычно с st.cache_data)
  • logic.py содержит чистые функции обработки pandas
  • ui.py содержит функции, которые рисуют части интерфейса
  • Так вы получаете “компоненты” на уровне Python: повторно используемые функции, которые легко тестировать и переносить.

    Компоненты интерфейса: собираем страницу из блоков

    В контексте учебного проекта под компонентами удобно понимать два уровня:

  • функциональные компоненты как Python-функции, рисующие часть страницы
  • переиспользуемые блоки интерфейса через контейнеры Streamlit (st.container, st.expander, st.tabs, st.sidebar)
  • Если вы хотите настоящие кастомные компоненты (React/JS), у Streamlit есть отдельный механизм.

  • Custom Components
  • Паттерн: UI-функции, которые принимают данные и возвращают выбор

    Идея: render_filters отвечает только за UI и возвращает параметры, а render_report отвечает только за отображение.

    Паттерн: контейнеры для управляемой перерисовки

    Streamlit часто удобно “собирать” в логические блоки:

  • st.sidebar для настроек
  • st.tabs для больших разделов
  • st.expander для второстепенных деталей
  • Сквозной пример: быстрое приложение “Импорт → фильтры → отчёт”

    Ниже каркас, который повторяет будущий проектный сценарий, но с акцентом на архитектуру и производительность.

    Что здесь сделано правильно:

  • чтение и базовая очистка кэшируются (st.cache_data), поэтому не повторяются на каждый клик
  • фильтры и отображение разделены по функциям
  • если файла нет, выполнение останавливается через st.stop(), и лишний код не выполняется
  • Частые ошибки производительности и как их исправить

  • Загрузка файла или запрос к API происходит на каждый перезапуск
  • - исправление: вынесите в функцию с st.cache_data
  • Тяжёлый объект создаётся каждый раз заново
  • - исправление: создавайте его в st.cache_resource
  • Смешаны UI и обработка данных в одном месте
  • - исправление: вынесите обработку в чистые функции (их легче кэшировать и тестировать)
  • Состояние пользователя хранится в обычных переменных
  • - исправление: переносите долгоживущие значения в st.session_state

    Мини-чеклист перед проектом

  • Вы понимаете, что st.session_state хранит пользовательское состояние между перезапусками.
  • Вы используете st.cache_data для данных и вычислений, которые повторяются.
  • Вы используете st.cache_resource для ресурсов, которые долго создаются и долго живут.
  • Вы разделяете код на компоненты: функции/модули для UI, загрузки данных и логики.
  • 6. Тестирование и качество: проверки логики, мокирование, линтинг

    Тестирование и качество: проверки логики, мокирование, линтинг

    Streamlit-приложения быстро собираются, но из-за постоянных перезапусков скрипта и активной работы с данными легко получить хрупкий код: где-то сломался парсинг CSV, API начал отвечать медленнее, а фильтры внезапно перестали работать после небольшого рефакторинга.

    В этой статье вы научитесь добавлять в проект слой качества:

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

  • из темы про архитектуру вы уже знаете идею разделения UI / data / logic
  • из темы про работу с данными у вас есть функции очистки и загрузки
  • из темы про производительность вы понимаете, почему важны чистые функции для кэша и тестов
  • !Схема показывает, что тестировать лучше всего чистую логику, а внешние зависимости изолировать моками

    Что именно тестировать в Streamlit-проекте

    Тестировать можно всё, но с максимальной отдачей обычно тестируют не UI, а то, что под ним.

    Уровни проверок

  • Юнит-тесты: проверяют небольшие функции (очистка данных, фильтры, агрегации). Самые быстрые и полезные.
  • Интеграционные тесты: проверяют связку модулей (например, функция загрузки CSV плюс очистка). Медленнее, но ловят ошибки на границах.
  • UI-тесты: проверяют, что интерфейс работает как ожидается. Для учебного проекта часто можно ограничиться минимумом, потому что они самые дорогие.
  • Практическое правило для курса:

  • основную логику выносите в src/logic.py и тестируете через pytest
  • работу с внешними источниками (requests, чтение файлов) тестируете с моками и временными файлами
  • Streamlit UI держите максимально тонким: собрать ввод, вызвать логику, отрисовать результат
  • Архитектура, которая “просит” тесты

    Если у вас всё в app.py, тестирование превращается в борьбу с st.* и перезапусками. Поэтому в проекте лучше закрепить структуру из прошлой статьи:

    Распределение ответственности:

  • ui.py: функции, которые рисуют интерфейс и читают виджеты
  • data.py: загрузка CSV/API и кэширование
  • logic.py: чистые функции преобразований и расчётов
  • Ключевой принцип тестируемости:

  • чем меньше внутри функции Streamlit-состояния (st.session_state) и I/O (файлы, сеть), тем проще её проверить
  • Юнит-тесты на pytest: базовый набор

    Для тестов в Python чаще всего используют pytest.

    Ссылки:

  • pytest documentation
  • Установка:

    Запуск:

    Пример логики, которую мы будем тестировать

    Пусть у вас есть функции обработки данных (это типично для тем про pandas и фильтры).

    src/logic.py:

    Тут важно, что:

  • функции возвращают новый DataFrame и не зависят от Streamlit
  • они детерминированы: одинаковый вход даёт одинаковый выход
  • Тест на чистку данных

    tests/test_logic.py:

    На что обращать внимание:

  • тест проверяет поведение, а не “внутренности”
  • входные данные в тесте маленькие и читаемые
  • Когда полезны фикстуры pytest

    Фикстуры помогают не повторять подготовку данных.

    Фикстуры особенно удобны, когда один и тот же датафрейм используют несколько тестов.

    Тестирование работы с файлами без Streamlit

    Streamlit даёт st.file_uploader, но проверять лучше вашу функцию, которая умеет читать данные.

    Вариант: функция принимает файловый путь

    Это самый простой вариант для тестов.

    src/data.py:

    tests/test_data.py:

    Почему это удобно:

  • tmp_path создаёт временную директорию, тест не зависит от файлов в репозитории
  • Мокирование: как тестировать API и “плохую сеть”

    Мокирование нужно, когда у функции есть внешняя зависимость:

  • HTTP-запросы
  • время
  • случайность
  • база данных
  • Главная цель: сделать тест предсказуемым.

    Ссылка:

  • unittest.mock — mock object library
  • Пример: функция загрузки постов из API

    src/data.py:

    Тест: подменяем requests.get

    tests/test_data.py:

    Что здесь происходит:

  • patch заменяет requests.get внутри модуля src.data
  • тест проверяет, что вы правильно обработали ответ, не делая реальный запрос
  • Тест: имитируем ошибку сети

    Этот тест полезен, потому что показывает: какое поведение ожидается при сбое сети.

    Линтинг, форматирование и типы: минимальный набор качества

    Тесты ловят ошибки в логике, но не заменяют инструменты, которые ловят проблемы раньше:

  • опечатки, неиспользуемые переменные
  • небезопасные конструкции
  • несогласованный стиль
  • ошибки типов в функциях
  • Ruff: быстрый линтер и автофиксы

    Ruff заменяет целый набор линтеров и работает очень быстро.

    Ссылки:

  • Ruff documentation
  • Установка:

    Запуск:

    Автоисправления (где возможно):

    Black: единый стиль форматирования

    Black форматирует код одинаково у всех участников проекта.

    Ссылки:

  • Black documentation
  • Установка и запуск:

    Mypy: проверка типов

    Типы особенно полезны в слоях data.py и logic.py, где много dict, list[dict], DataFrame.

    Ссылка:

  • Mypy documentation
  • Запуск:

    Практическая рекомендация:

  • начните с аннотаций входов/выходов функций
  • не пытайтесь “затипизировать” всё сразу
  • Pre-commit: чтобы качество проверялось автоматически

    pre-commit позволяет запускать линтеры и форматтеры автоматически перед коммитом.

    Ссылка:

  • pre-commit
  • Типовой подход:

  • добавить ruff, black (и при желании mypy) в хуки
  • зафиксировать единое качество для всей команды и для вас “из будущего”
  • CI в проекте: тесты и линтеры на каждом пуше

    Когда вы будете собирать итоговый проект курса, полезно запускать проверки автоматически в CI.

    Популярный вариант для учебных репозиториев:

  • GitHub Actions
  • Ссылка:

  • GitHub Actions documentation
  • Логика пайплайна обычно такая:

  • поставить зависимости
  • запустить ruff
  • запустить black --check
  • запустить pytest
  • Практический чеклист качества для проекта курса

  • Логика вынесена в src/logic.py и покрыта юнит-тестами.
  • Внешние вызовы (requests.get) тестируются через моки.
  • Чтение файлов тестируется через tmp_path, без реальных файлов в репозитории.
  • В проекте включены ruff и black.
  • Минимальные аннотации типов добавлены в ключевые функции.
  • Перед отправкой проекта запускается хотя бы: ruff check . и pytest.
  • 7. Итоговый проект: дизайн, реализация, деплой и презентация

    Итоговый проект: дизайн, реализация, деплой и презентация

    Итоговый проект курса нужен, чтобы собрать всё изученное в одну цельную работу: интерактивный Streamlit-сервис, который берёт данные, обрабатывает их, показывает отчёт, работает быстро, покрыт тестами и готов к публикации.

    В предыдущих статьях вы освоили:

  • запуск и устройство Streamlit-приложения
  • виджеты, формы и st.session_state
  • таблицы, графики, компоновку страницы
  • загрузку файлов, API, pandas, обработку
  • производительность через st.cache_data и st.cache_resource
  • тестирование логики, мокирование, линтинг
  • Теперь вы соберёте готовый продукт: от идеи и дизайна до деплоя и презентации.

    Концепция итогового проекта

    Рекомендуемая тема проекта

    Выбирайте тему, которая естественно использует всё из курса. Универсальный вариант для учебного проекта:

  • Интерактивный отчёт по данным из CSV и/или API с фильтрами, метриками, графиками и выгрузкой результата
  • Пример формулировки проекта:

  • Data Explorer: загрузка CSV, очистка, фильтрация, отчёт, экспорт
  • Почему это хороший выбор:

  • данные можно тестировать локально
  • UI получается наглядным
  • легко продемонстрировать кэш, состояние, архитектуру и качество
  • Минимальные требования к итоговому проекту

    Проект считается полноценным, если в нём есть:

  • загрузка данных из файла или API
  • базовая очистка и преобразование данных в pandas
  • фильтры в интерфейсе
  • таблица и минимум один график
  • кэширование в “дорогих” местах
  • хранение пользовательского состояния в st.session_state
  • хотя бы несколько тестов для логики
  • оформление репозитория: README.md, зависимости, структура
  • Проектирование: что именно вы строите

    Пользовательский сценарий

    Начинайте с одного сценария, который можно описать коротко:

  • пользователь открывает приложение
  • загружает CSV
  • выбирает фильтры
  • видит отчёт
  • скачивает обработанный результат
  • Если у вас есть API-режим, добавьте альтернативную ветку:

  • пользователь выбирает “Источник: API”
  • нажимает “Загрузить”
  • видит данные и отчёт
  • Дизайн интерфейса

    Проектируйте страницу как набор блоков:

  • сайдбар: источник данных и фильтры
  • основная область: вкладки Отчёт / Данные / Диагностика
  • Хорошие практики интерфейса Streamlit:

  • фильтры и настройки держите в st.sidebar
  • большие части разделяйте st.tabs
  • технические детали прячьте в st.expander
  • ошибки показывайте через st.error и st.exception
  • !Макет страницы и расположение ключевых блоков UI

    Архитектура проекта: как разложить код

    Лучший способ упростить тестирование и сопровождение: разделить UI, данные и логику.

    Рекомендуемая структура репозитория

    Роли модулей:

  • app.py: точка входа, сборка страницы, маршрутизация по вкладкам
  • src/ui.py: функции, которые рисуют интерфейс и возвращают значения фильтров
  • src/data.py: загрузка данных из файла и API, кэширование
  • src/logic.py: чистые функции pandas для очистки, фильтров, агрегаций
  • src/settings.py: константы, названия колонок, дефолты
  • Такой дизайн напрямую поддерживает подходы из статей про производительность и тестирование.

    !Схема модульной архитектуры приложения

    Реализация: сборка по шагам

    Шаги разработки

    Ниже последовательность, которая помогает не “утонуть” в проекте.

  • Создайте скелет приложения
  • Добавьте загрузку данных
  • Добавьте очистку и валидацию
  • Добавьте фильтры
  • Добавьте отчёт: метрики, графики, таблицы
  • Добавьте экспорт результата
  • Оптимизируйте производительность
  • Добавьте тесты и линтеры
  • Подготовьте деплой
  • Подготовьте презентацию
  • Каркас app.py

    Общий принцип: app.py содержит минимум логики и максимум “склейки”.

    Идея:

  • загрузка данных и бизнес-логика вынесены в src
  • UI-функции возвращают значения, а не хранят логику внутри себя
  • Загрузка данных: файл и API

    В src/data.py удобно сделать единый интерфейс загрузки:

  • если источник “file”, читаем st.file_uploader
  • если источник “api”, делаем requests.get
  • Кэшируйте:

  • чтение CSV и тяжёлую подготовку через st.cache_data
  • создание клиентов, сессий, моделей через st.cache_resource
  • Документация:

  • Streamlit caching
  • Очистка, фильтры, отчёт

    Логику обработки держите в чистых функциях:

  • clean_df(df): типы, пропуски, нормализация колонок
  • apply_filters(df, filters): фильтрация по выбранным параметрам
  • build_report(df): расчёт агрегатов и подготовка данных для графиков
  • Такую логику:

  • легко тестировать pytest
  • легко кэшировать, если нужно
  • проще переносить между проектами
  • Производительность: что кэшировать, а что держать в состоянии

    Правило разделения ответственности

  • st.session_state: пользовательские действия и режимы интерфейса
  • st.cache_data: результаты функций загрузки и расчётов
  • st.cache_resource: долгоживущие “тяжёлые” объекты
  • Пара типовых примеров того, что класть в st.session_state:

  • “режим источника данных”
  • “последний загруженный файл” как факт выбора, а не как DataFrame
  • “показывать ли расширенные детали”
  • Пара типовых примеров того, что кэшировать через st.cache_data:

  • чтение CSV
  • запрос к API с ttl
  • тяжёлая группировка/агрегация
  • Качество: тесты, линтинг, типы

    Минимальный набор для учебного проекта

  • pytest для логики
  • мокирование requests.get при тестировании API
  • ruff для линтинга
  • black для форматирования
  • Ссылки:

  • pytest
  • unittest.mock
  • Ruff
  • Black
  • Что тестировать в первую очередь

  • функции очистки pandas
  • функции фильтрации
  • расчёт агрегатов для отчёта
  • работу с API через моки
  • UI в Streamlit в учебном проекте обычно достаточно проверять вручную, если логика вынесена в тестируемые функции.

    Деплой: как опубликовать приложение

    Вариант: Streamlit Community Cloud

    Это самый простой способ для учебного проекта:

  • код лежит в GitHub
  • Streamlit Cloud собирает зависимости и запускает streamlit run app.py
  • секреты добавляются через настройки приложения
  • Документация:

  • Streamlit Community Cloud
  • Что нужно подготовить:

  • публичный репозиторий на GitHub
  • requirements.txt или pyproject.toml
  • app.py в корне проекта
  • опционально packages.txt, если нужны системные пакеты
  • Про секреты:

  • Secrets management
  • Вариант: Docker (если нужен универсальный деплой)

    Docker полезен, если вы хотите одинаковый запуск локально и на сервере.

    Справочная документация:

  • Streamlit deployment overview
  • !Варианты деплоя и точки, где хранятся секреты

    Презентация проекта: как защитить работу

    Хорошая презентация показывает не только интерфейс, но и инженерную зрелость.

    Что показать за 5–7 минут

  • задача и целевой пользователь
  • источник данных и пример входных данных
  • сценарий работы: загрузка, фильтры, отчёт, экспорт
  • производительность: где использован кэш и почему
  • качество: какие тесты написаны и что проверяют
  • деплой: ссылка на работающий сервис и как его запустить локально
  • Что обязательно написать в README.md

  • краткое описание проекта
  • требования к окружению
  • установка зависимостей
  • запуск локально
  • как запустить тесты
  • как устроен проект по папкам
  • пример данных или описание формата входного CSV
  • Пример команд для README:

    Финальный чеклист перед сдачей

  • приложение запускается локально без ручных правок
  • ошибки ввода обработаны и показываются понятным сообщением
  • тяжёлые места ускорены кэшем
  • пользовательское состояние не “теряется” между кликами
  • логика лежит в src/logic.py и покрыта тестами
  • зависимости зафиксированы
  • репозиторий содержит понятный README.md
  • приложение задеплоено или есть инструкции деплоя
  • Куда развивать проект дальше

    Если вы хотите сделать проект сильнее, выбирайте одно улучшение за раз:

  • поддержка нескольких форматов данных (CSV, Excel)
  • сохранение пользовательских “настроек отчёта” в st.session_state
  • дополнительные источники данных (ещё один API)
  • более сложные графики через Altair или Plotly
  • CI в GitHub Actions для автоматического запуска ruff и pytest
  • Документация по общей разработке на Streamlit:

  • Streamlit API reference