Обзор marimo: реактивный Python-ноутбук показывает инструмент, который хранит вычисления как файл .py, строит граф зависимостей по именам переменных и автоматически пересчитывает зависимые ячейки. Документация проекта на docs.marimo.io описывает его как открытый реактивный Python-ноутбук, исполняемый как скрипт и разворачиваемый как приложение.
Как работает реактивность
Ячейка в marimo — небольшой блок Python-кода. Когда вы запускаете ячейку, среда автоматически запускает все ячейки, которые читают глобальные переменные, определённые в ней. Это и есть реактивное исполнение: документация проекта называет его основой поведения ноутбука.
Порядок ячеек на странице не влияет на порядок исполнения. Очерёдность определяется тем, какие переменные ячейка определяет и какие читает. marimo статически анализирует код ячеек и строит направленный ациклический граф по глобальным именам. При редактировании зависимостей граф должен соответствовать новому коду. Этот граф и задаёт поток данных.
Практическое следствие: удаление ячейки убирает её переменные из памяти программы. Так среда устраняет устаревшие глобальные определения, оставшиеся от удалённого кода. Внешние данные, мутации и побочные эффекты всё равно требуют отдельного контроля. Документация проекта подчёркивает, что это решает многие проблемы традиционных ноутбуков.
Реактивность не требует специального синтаксиса. Ячейки остаются чистым Python. В редакторе ячеек для включения пересчёта не нужно писать дополнительные декораторы или особый API — среда выводит зависимости из обычного кода.
Пределы начинаются там, где анализ по именам перестаёт видеть происходящее. marimo не отслеживает мутации объектов во время исполнения. Если нужно изменить переменную — например, добавить столбец в датафрейм, — мутацию выполняют в той же ячейке, где переменная определена. Иначе граф не увидит связь.
Второй предел — циклы. Граф ациклический, поэтому взаимные зависимости ячеек недопустимы. Третье — побочные эффекты: отправка сообщения, запись файла или платёжный вызов внутри автоматически пересчитываемой ячейки повторятся при каждом обновлении зависимости. Такие действия выносят за пределы реактивной формулы.
Учебный граф и эталон проверки
Возьмём простой граф из трёх ячеек. Это условный учебный вход для арифметической демонстрации. Редакция ноутбук не запускала.
Ячейка 1 задаёт prices=[100,200,300] и discount=0.1. Ячейка 2 вычисляет net=[p*(1-discount) for p in prices]. Ячейка 3 считает total=sum(net). Граф связей: 1→2→3.
Эталон при скидке 0.1: net=[90,180,270], total=540. После изменения discount=0.2 ожидаем net=[80,160,240], total=480. В реактивном режиме зависимые ячейки пересчитываются сразу. В ленивом режиме они помечаются неактуальными до запуска.
Карточка проверки: измените скидку на 0.2, сверьте net и total с эталонами, объясните конфликт при втором определении discount в другой ячейке, вынесите отправку сообщения из автоматически пересчитываемой формулы, чтобы не повторить внешний эффект. Для воспроизводимости отдельно нужны исходные данные и версии зависимостей.
| Шаг | Действие | Ожидаемый результат |
|---|---|---|
| 1 | Задать prices, discount=0.1 |
Ячейка 1 исполнена |
| 2 | Вычислить net |
[90,180,270] |
| 3 | Суммировать total |
540 |
| 4 | Сменить discount=0.2 |
Пересчёт зависимых ячеек |
| 5 | Сверить net и total |
[80,160,240], 480 |
Ленивый режим и дорогие вычисления
Реактивный пересчёт удобен на быстрых операциях и опасен на дорогих. Документация проекта описывает настройку runtime в режим lazy: затронутые ячейки помечаются как неактуальные, автоматический запуск не происходит. Это даёт гарантии на состояние программы и предотвращает случайное исполнение дорогих ячеек.
Разница практическая. В реактивном режиме правка скидки мгновенно пересчитывает весь граф ниже. В ленивом режиме вы видите пометку неактуальности и сами решаете, когда запускать. Для обучения и разведки данных подходит первый вариант, для тяжёлых пайплайнов — второй.
Ленивый режим не отменяет граф зависимостей. Он меняет момент исполнения, сохраняя понимание того, какие ячейки затронуты. Это компромисс между свежестью результата и стоимостью вычисления.
Сравнение с Jupyter по порядку исполнения
Документация проекта проводит сравнение с Jupyter именно по порядку исполнения. В Jupyter код на странице может расходиться с выводами и состоянием программы: удалённая ячейка оставляет переменные в памяти, а ячейки можно запускать в произвольном порядке. Одна работа, упомянутая в FAQ проекта, проанализировала 10 миллионов ноутбуков Jupyter и обнаружила, что 36% из них невоспроизводимы.
В реактивном режиме marimo поддерживает согласованность вычислений по обнаруженным зависимостям. В lazy mode неактуальный вывод получает соответствующую пометку. Ни один режим сам не фиксирует содержимое внешнего файла и не исправляет ошибочную формулу.
| Критерий | marimo | Jupyter |
|---|---|---|
| Порядок исполнения | По графу переменных | Произвольный, вручную |
| Устаревшие глобальные определения | Удаление ячейки удаляет её определения | Могут оставаться в работающем ядре |
| После изменения зависимости | Пересчёт или отметка неактуальности в lazy mode | Порядок повторного запуска контролирует пользователь |
Документация проекта также отмечает: ноутбуки marimo можно импортировать как модули, извлекать из них функции и классы в другие программы. В Jupyter это делается сложнее.
Структурная и фактическая корректность
Разведём два уровня проверки. Структурная корректность означает, что граф зависимостей построен без циклов, каждое имя определено один раз, а порядок ячеек не влияет на исполнение. Фактическая правильность означает, что числа в результате совпадают с ожидаемым эталоном.
Инструмент проверяет обнаруженные зависимости и сообщает о структурных конфликтах. Правильность арифметики по требованиям задачи остаётся отдельной проверкой. Если в ячейке 2 формула написана как p*(1+discount), граф останется корректным, а результат будет неверным. Реактивность поддерживает связи. Соответствие формулы условию задачи проверяет автор.
Второе определение discount в другой ячейке даст конфликт: одно имя, два определения. Среда сообщит об ошибке, потому что граф требует единственного владельца имени. Это структурная проверка, помогающая поймать случайное дублирование.
Практический вывод: реактивность убирает класс ошибок, связанных с порядком и устаревшим состоянием, и оставляет класс ошибок, связанных с логикой формул. Проверять эталонные значения всё равно нужно вручную.
Где подход не решает задачу
Реактивный граф плохо ложится на сценарии с побочными эффектами. Отправка письма, запись в базу, вызов внешнего API внутри автоматически пересчитываемой ячейки повторятся при каждом изменении зависимости. Такие действия выносят из автоматически пересчитываемой формулы и проектируют явный запуск. Простое перемещение в другую зависимую ячейку не устраняет повтор: нужно проверить режим исполнения и условие запуска этой ячейки.
Дорогие вычисления — второй случай. Обучение модели или тяжёлый запрос к хранилищу в реактивной ячейке запустится при каждом касании зависимости. Ленивый режим смягчает проблему, но не отменяет необходимости проектировать граф аккуратно.
Третий случай — работа с изменяемыми объектами. marimo не отслеживает мутации во время исполнения, поэтому изменение датафрейма вне определяющей ячейки не вызовет пересчёт. Приходится держать мутацию рядом с определением.
Наконец, файл .py сам по себе не фиксирует внешние данные и версии библиотек. Ноутбук может содержать требования к пакетам внутри файла, а lock-файлы скриптов записывают разрешённые версии зависимостей для передачи. Воспроизводимость результата требует отдельной заботы об окружении.
Запуск, редакторы и развёртывание
Документация проекта предлагает начать с molab — бесплатного онлайн-ноутбука — либо установить marimo локально через менеджер пакетов. Ноутбук запускается как скрипт из командной строки и разворачивается как интерактивное веб-приложение командой marimo run.
Редактор поддерживает GitHub Copilot, AI-ассистентов, раскладку vim, обозреватель переменных. Работать можно в VS Code, Cursor, neovim, Zed или любом текстовом редакторе. Есть нативная поддержка SQL для запросов к датафреймам, базам, хранилищам и lakehouse.
Отдельный слой — облачные развёртывания. Документация Carolina Cloud описывает преднастроенный образ Data Science Notebook с polars, pandas, scikit-learn, PyTorch, matplotlib, plotly и более чем 20 пакетами. При добавлении GPU доступны библиотеки RAPIDS и cuDF. Эти настройки относятся к конкретному облачному продукту Carolina Cloud и не переносятся на стандартный marimo.
Там же описаны S3-предзаполнение при создании инстанса, автонастройка панелей AI при передаче ключа Anthropic и авто-стоп после окна простоя CPU. Это конфигурация конкретного провайдера.
Частые вопросы
Чем marimo отличается от Jupyter?
Документация проекта сравнивает их по порядку исполнения. В Jupyter ячейки запускаются вручную и в произвольном порядке, а удаление ячейки оставляет переменные в памяти. marimo строит граф по переменным и пересчитывает зависимые ячейки автоматически. Ноутбук хранится как чистый .py и исполняется как скрипт.
Как запустить marimo онлайн?
Документация проекта предлагает molab — бесплатный онлайн-ноутбук для быстрого старта. Локально marimo ставится через менеджер пакетов. Развёртывание как веб-приложение выполняется командой marimo run. Конкретные условия доступа из России в источниках не раскрыты.
Как marimo работает с секретами и ключами?
Документация Carolina Cloud описывает передачу ключа Anthropic при создании инстанса: панели AI-автодополнения, редактирования и чата подключаются автоматически. Это настройка конкретного облачного продукта. Для стандартного marimo документация проекта упоминает возможность принести собственные API-ключи и локальные модели.
Поддерживает ли marimo GPU?
Документация Carolina Cloud указывает, что образ Data Science Notebook поддерживает подключение GPU. При выделении GPU в ячейках доступны PyTorch CUDA и RAPIDS. Это относится к конкретному облачному предложению Carolina Cloud. Стандартный marimo сам по себе GPU не предоставляет — он использует то окружение, в котором запущен.
Где хранятся ноутбуки marimo?
Каждый ноутбук хранится как файл .py, пригодный для версионирования в Git. Документация проекта отмечает, что требования к пакетам можно держать внутри файла ноутбука, а lock-файлы скриптов записывают разрешённые версии зависимостей. Файл .py не фиксирует внешние данные и версии библиотек сам — об окружении нужно позаботиться отдельно.
