marimo 迁移指南:从 Jupyter、Streamlit、Jupytext、Papermill 平滑切换
2026/9/13 12:00:38 网站建设 项目流程

marimo 迁移指南:从 Jupyter、Streamlit、Jupytext、Papermill 平滑切换

【免费下载链接】marimoA reactive notebook for Python — run reproducible experiments, query with SQL, execute as a script, deploy as an app, and version with git. Stored as pure Python. All in a modern, AI-native editor.项目地址: https://gitcode.com/GitHub_Trending/ma/marimo

marimo 是一个"单一工具"替代方案,目标是用一个工具取代jupyterstreamlitjupytextipywidgetspapermill等一整套生态。本文以 docs/guides/coming_from 系列文档为主体,系统性对比 marimo 与 Jupyter、Streamlit、Jupytext、Papermill 的核心差异,给出可复制的迁移示例、等价 API 对照表与执行模型适配建议,帮助读者在迁移后直接上手 marimo 的响应式执行、纯 Python 文件格式、CLI 参数注入与程序化执行能力。

总览:marimo 在工具生态中的定位

marimo 的核心主张是:notebook-first 的编程环境,同时天然具备脚本与应用能力。它取代的不只是某一个工具,而是从交互式开发、应用搭建、文本化存储到流水线执行的整条链路:

被替代工具marimo 中的对应能力
Jupyter响应式 notebook 环境,单元之间通过变量依赖构成数据流图
Streamlit同一份 notebook 直接以marimo run运行成交互式 Web 应用
Jupytextnotebook 原生以纯 Python(.py)存储,无需配对同步
Papermill内置mo.cli_args/mo.query_params参数注入与程序化执行 API

从仓库结构看,marimo/_runtime 承载了上述能力的运行时核心:cli_argsquery_params的实现位于 marimo/_runtime/runtime.py,参数对象的类型定义在 marimo/_runtime/params.py 附近,CLI 的runeditconvertexport等子命令定义于 marimo/_cli/cli.py。后续各节将围绕这些实现展开说明。


一、从 Jupyter 迁移:理解 marimo 的执行模型

1.1 核心差异:REPL 与响应式数据流图

Jupyter 本质是一个REPL:代码块逐段执行,Jupyter 并不理解不同代码块之间的依赖关系。这种模型容易累积"隐藏状态"——你可能不小心乱序执行单元,或运行/删除了某个单元却忘记重跑依赖它的单元,导致 notebook 难以复现。

marimo 则不同:它在运行时把 notebook 的所有单元"编译"成一张以变量声明与引用为边的有向图(见 docs/guides/reactivity.md)。单元之间由变量依赖自动关联,从而消除隐藏状态;也正是这张图,让 notebook 可以被复用作应用与脚本。

默认行为:运行某个单元时,所有读取其变量的其他单元会自动重跑,以保证代码与输出始终同步。刚迁移时这可能需要一段时间适应,仓库提供了两种缓解手段:

  • 配置运行时:参考 docs/guides/configuration/runtime_configuration.md,可关闭"启动时自动运行""执行单元后自动运行"等选项。即使关闭自动运行,marimo 仍会跟踪跨单元依赖,把受影响单元标记为 stale,你只需点击一次按钮即可重跑所有过期单元。
  • mo.stop手动控制执行mo.stop(condition)在条件满足时中止当前单元继续执行,常用于"必须点击按钮才执行昂贵计算"的场景:
# 如果 condition 为 True,mo.stop() 返回后单元停止执行 mo.stop(condition) # 若 condition 为 True,这行不会执行 expensive_function_call()

结合mo.ui.run_button()的典型用法(这也是 docs/guides/coming_from/jupyter.md 中给出的示例):

# 单元 A run_button = mo.ui.run_button() run_button # 单元 B mo.stop(not run_button.value, mo.md("点击 👆 运行此单元")) mo.md("你点击了按钮!🎉")

针对"昂贵 notebook"的更多适配技巧,见 docs/guides/expensive_notebooks.md。

1.2 变量重定义约束与 dataframe 迁移技巧

由于 marimo 需要确定单元的排序,同一个变量不能在多个单元中被重复定义。仓库建议的三种适配方式:

  1. 尽可能把代码封装进函数,减少全局变量;
  2. 用下划线前缀(_my_temporary)声明单元局部变量
  3. 在定义变量的那个单元内完成对该变量的修改。

对于 dataframe,Jupyter 用户习惯在多个单元里反复改写同一个df,这在 marimo 中行不通。正确做法是把操作合并进单个单元:

df = pd.DataFrame({"my_column": [1, 2]}) df["another_column"] = [3, 4]

若确实需要跨单元变换,可以给 dataframe 起别名:

df = pd.DataFrame({"my_column": [1, 2]}) augmented_df = df augmented_df["another_column"] = [3, 4]

1.3 文件格式:Python 而非 JSON

marimo 把 notebook 存成 Python 文件而非 JSON,由此获得的能力包括:用 git 版本化、作为脚本执行(见 docs/guides/scripts.md)、在其他 Python 文件中导入具名单元。代价是输出(如图表)不保存在文件里

  • 保存输出快照:启用编辑器中的 "Auto-download as HTML/IPYNB" 设置(见 docs/guides/configuration/index.md),marimo 会定期把 notebook 快照为 HTML 或 ipynb,存放在 notebook 目录下的__marimo__文件夹;也可用marimo export命令手动导出。
  • 在 GitHub 上预览输出:可以把导出的 ipynb 提交进版本控制,GitHub 会直接渲染输出。
  • 存储细节提醒:不同指南对快照目录的表述略有差异(jupyter.md 中为__marimo__文件夹,papermill.md 中为.marimo/目录),迁移时请以你安装版本编辑器的实际行为为准。

1.4 转换命令:双向转换

Jupyter → marimo(命令行):

marimo convert your_notebook.ipynb -o your_notebook.py

Python 脚本 → marimo

marimo convert your_script.py -o your_notebook.py
  • py:percent 格式:脚本使用# %%单元标记时,marimo 会转换为多单元 notebook(需安装 jupytext);
  • 普通 Python 脚本:没有单元标记时转换为单单元 notebook。

用 uv 进行 py:percent 转换:

uvx --with=jupytext marimo convert your_script.py -o your_notebook.py

marimo → Jupyter

marimo export ipynb notebook.py -o notebook.ipynb

注意:部分 marimo 库函数(尤其是 UI 元素)在 Jupyter notebook 中无法工作。

1.5 Magic 命令替代方案

marimo notebook 就是纯 Python,因此不支持 IPython magic 命令,也不支持!前缀的 shell 命令。替代方式如下:

import subprocess # 等价于运行 "ls -l" subprocess.run(["ls", "-l"])

常见 magic 命令的等价替代:

Magic 命令marimo/Python 替代
%cdos.chdir(),另见mo.notebook_dir()
%clear右键单元或切换单元操作菜单
%debugPython 内置调试器breakpoint()
%envos.environ
%load使用 Python import
%load_ext无对应
%autoreloadmarimo 的模块自动重载(见 docs/guides/editor_features/module_autoreloading.md)
%matplotlibmarimo 自动显示绘图
%pwdos.getcwd()
%pipmarimo 内置包管理(见 docs/guides/editor_features/package_management.md)
%who_lsdir()globals()mo.refs()mo.defs()
%systemsubprocess.run()
%%timetime.perf_counter()或 timeit 模块
%%timeittimeit 模块
%%writefilewith open("file.txt", "w") as f: f.write(...)
%%capturemo.capture_stdout()mo.capture_stderr()
%%htmlmo.Html()mo.md()
%%latexmo.md(r'$$...$$')

包安装则直接使用 marimo 的包管理侧边栏面板,它会安装到当前环境。


二、从 Streamlit 迁移:notebook-first 的数据应用

2.1 关键差异

Streamlit 是应用框架,marimo 首先是响应式 notebook 环境,两者的定位差异带来一系列不同:

  1. Notebook 即应用:Streamlit 开发数据应用时常先原型于 Jupyter、再重构迁移;marimo 中每个 notebook 本身就是应用,用marimo run即可运行,无需迁移步骤。
  2. 执行性能:marimo 采用响应式执行模型,交互或代码变化时只重跑维持 notebook 最新状态所需的最小单元集合;Streamlit 每次交互都重跑整个脚本,容易引发性能问题。
  3. 文件格式:两者都是纯 Python 文件,但 marimo 的文件结构支持更细粒度的响应式;且 marimo 文件可以直接作为 Python 脚本执行、可以被其他程序 import 复用(例如通过marimo.Cell.run复用单元,见 docs/api/cell.md)。
  4. UI 元素:两者都提供滑块、文本框、表格等元素。Streamlit 创建元素即自动输出;marimo 将"创建"与"显示"分离,可以自由组合布局、构造高阶元素,甚至把同一个元素输出两次。
  5. 自定义组件:marimo 支持 anywidget 规范,可直接复用为 Jupyter 生态开发的 widget;Streamlit 使用自己的自定义组件体系。
  6. 内置编辑器:marimo 自带专为数据工作设计的内置编辑器(见 docs/guides/editor_features/index.md),Streamlit 依赖外部编辑器。
  7. 数据工作流:marimo 的 notebook 环境适合迭代式探索开发,内置原生 SQL 支持(见 docs/guides/working_with_data/sql.md);Streamlit 专用于构建独立数据应用。

2.2 常见 Streamlit 功能的 marimo 等价写法

1. 显示文本

# Streamlit import streamlit as st st.markdown("# Greetings\nHello world") # marimo import marimo as mo mo.md("# Greetings\nHello world")

2. 显示数据

# Streamlit st.dataframe(df) # marimo:单元最后一个表达式自动显示 df

3. 输入控件

# Streamlit age = st.slider("How old are you?", 0, 130, 25) # marimo:创建与显示分离,值通过 .value 访问,可与文本任意组合 age = mo.ui.slider(label="How old are you?", start=0, stop=130, value=25) mo.md(f"One more question: {age}")

4. 按钮

# Streamlit if st.button("Click me"): st.write("Button clicked!") # marimo:按钮对象 + 另一单元读取 .value button = mo.ui.run_button("Click me") # 在另一个单元中 if button.value: mo.output.replace(mo.md("Button clicked!")) # 或者 mo.md("Button clicked!") if button.value else None

5. 基本布局

# Streamlit col1, col2 = st.columns(2) with col1: st.write("Column 1") with col2: st.write("Column 2") # marimo mo.hstack([ mo.md("Column 1"), mo.md("Column 2") ])

6. 高级布局(折叠面板)

# Streamlit with st.expander("Expand me"): st.write("Hello from the expander!") # marimo:可无限嵌套,组合更灵活 mo.accordion({"Expand me": "Hello from the expander!"})

7. 绘图

# Streamlit import matplotlib.pyplot as plt fig, ax = plt.subplots() ax.plot([1, 2, 3, 4]) st.pyplot(fig) # marimo:最后一个表达式自动显示 import matplotlib.pyplot as plt plt.plot([1, 2, 3, 4]) plt.gca()

8. 缓存

# Streamlit @st.cache_data def expensive_computation(args): ... # marimo @mo.cache def expensive_computation(args): ...

marimo 提供mo.cachemo.lru_cache(缓存函数返回值)以及mo.persistent_cache(把变量持久化到磁盘),详见 docs/api/caching.md。

9. 会话状态

Streamlit 用st.session_state持久化数据;marimo 中直接用普通 Python 变量即可——对于未被重新执行的单元,notebook 会为其维护一致的状态。

10. 作为应用运行

# Streamlit streamlit run your_app.py # marimo marimo run your_notebook.py

2.3 迁移后需要记住的四条原则

  1. 单元在依赖变化时自动重跑,但只有受影响单元会重跑,效率远高于朴素实现的 Streamlit 程序;
  2. marimo 的 UI 元素通常赋值给变量,通过.value属性读取值;
  3. mo.md()非常灵活,可以用 f-string 同时组合文本与 UI 元素;
  4. notebook-first 的定位让 marimo 适用于各种数据工作:探索性数据分析、数据工程、机器学习实验与训练、库文档与示例等。

三、从 Jupytext 迁移:原生文本化存储

3.1 与 Jupytext 的本质区别

Jupytext 依赖配对与同步ipynb与文本表示之间需要额外配置、可能产生同步问题。marimo notebook默认就以.py存储,不存在同步问题。另外 Jupytext 服务于 IPython/Jupyter notebook,marimo notebook 并不基于 IPython/Jupyter。

marimo 还有 markdown 文件格式,可通过命令行marimo tutorial markdown-format学习;markdown 形式下没有特殊语法,在 GitHub 等平台渲染效果良好。

3.2 逐项对比

场景Jupytextmarimo
Notebook 格式用注释或特殊标记定义单元类型默认纯 Python(.py)文件,用标准 Python 语法(装饰器、函数)定义单元;markdown 形式(.md)无特殊语法,GitHub 渲染良好
.ipynb转换jupytext --to py notebook.ipynbmarimo convert notebook.ipynb > notebook.py
py:percent 转换marimo convert percent_notebook.py -o marimo_notebook.py(需 jupytext);uv 下为uvx --with=jupytext marimo convert percent_notebook.py -o marimo_notebook.py
导出到.ipynbjupytext --to notebook.ipynb notebook.pymarimo export ipynb notebook.py > notebook.ipynb
编辑需要在.ipynb.py之间同步直接在 marimo 编辑器marimo edit notebook.py编辑,读写同一文件
执行用 Jupyter 交互编辑,或用 Papermill 命令行执行交互运行marimo notebook.py;脚本运行python notebook.py;应用运行marimo run notebook.py,并内置 CLI 参数支持(见 docs/api/cli_args.md)
版本控制ipynb 默认是 JSON,git diff 难以阅读;需用 Jupytext 配对以获得小 diff已是.py格式,天然 git 友好,小改动保证产生小 diff
Markdown 与代码单元需要特殊标记或格式区分单元类型mo.md("...")写 Markdown,用mo.md(f"...")插值 Python 值,无魔法语法
部署需迁移到 Voila、Streamlit 等其他库直接用marimo run部署为交互式 Web 应用

四、从 Papermill 迁移:参数化与程序化执行

4.1 参数化 notebook:CLI 参数与 URL 查询参数

Papermill 通过定义 "parameters" 单元并在运行时注入值来实现参数化。marimo 提供两种内置方式:

方式一:命令行参数mo.cli_args()

import marimo as mo # 读取 CLI 参数 args = mo.cli_args() param1 = args.get("param1", "default_value")

作为脚本运行:

python notebook.py -- --param1 value1

作为应用运行:

marimo run notebook.py -- --param1 value1

从源码看,mo.cli_args()返回只读的CLIArgs字典(定义于 marimo/_runtime/params.py 附近,运行时实现见 marimo/_runtime/runtime.py),不能在 notebook 内修改。editrun等 CLI 子命令都接受nargs=-1的透传参数(见 marimo/_cli/cli.py),--之后的内容即注入 notebook 的 argv。

方式二:URL 查询参数mo.query_params()

import marimo as mo # 读取查询参数 params = mo.query_params() param1 = params.get("param1", "default_value")
marimo run notebook.py

然后访问:

http://your-app-url/?param1=value1

CLIArgs不同,QueryParams是可变的:修改它会被持久化到前端 URL,且引用该对象的其他单元会自动重跑。源码 marimo/_runtime/runtime.py 的 docstring 给出了典型用法——让文本框与 URL 参数双向同步:

# 独立单元 query_params = mo.query_params() # 另一单元 search = mo.ui.text( value=query_params["search"] or "", on_change=lambda value: query_params.set("search", value), ) search

4.2 程序化执行 notebook

marimo notebook 是纯 Python 文件,天然支持程序化执行:

1. 运行具名单元(marimo.Cell.run

from my_notebook import my_cell # last_expression 是该单元的视觉输出 # definitions 是该单元定义的变量字典 last_expression, definitions = my_cell.run()

该 API 也支持为单元输入传参,完整示例见 docs/api/cell.md 中marimo.Cell.run的说明。

2. 程序化运行整个应用并覆盖定义(app.run

import marimo from my_notebook import app # 覆盖单元定义后运行 # 这会完全替换定义这些变量的单元的返回定义 outputs, defs = app.run(defs={"batch_size": 64, "learning_rate": 0.001, "model_type": "transformer"})

重要限制(务必理解,避免踩坑):

  • 传入defs后,定义这些变量的单元逻辑完全被覆盖、不再执行
  • 必须提供某单元原本会产生的全部定义,而非个别参数;
  • 这与 CLI 参数不同——CLI 参数是在单元执行内部被解析的。

例如某个单元定义了:

@app.cell def config(): batch_size = 32 learning_rate = 0.01 return batch_size, learning_rate

覆盖时必须两个变量一起提供:

# 正确:覆盖该单元的全部定义 outputs, defs = app.run(defs={"batch_size": 64, "learning_rate": 0.001}) # 错误:会留下 learning_rate 未定义 # outputs, defs = app.run(defs={"batch_size": 64})

3. 子进程方式

import subprocess subprocess.run(["python", "notebook.py", "--", "--param1", "value1"])

4.3 存储与分享产物

需求命令/方式
导出为 HTMLmarimo export html notebook.py -o notebook.html -- -arg1 foo --arg2 bar
部署为 Web 应用marimo run notebook.py
编辑期自动导出在编辑器应用设置中开启 auto-export HTML,每次修改后自动生成 HTML 快照到 notebook 所在位置的.marimo/目录

4.4 集成进工作流

  1. 作为 Python 脚本:marimo notebook 就是 Python 文件,可直接在大多数工作流系统中执行(仓库 examples 目录提供与主流工具的集成示例);
  2. 程序化执行:把 notebook 作为 Python 模块 import,或通过 subprocess 执行,可在工作流中串联多个 notebook。

五、迁移速查:四类用户的下一步

你的来源最需要先掌握的能力参考文档
Jupyter响应式执行模型、变量不可重定义、magic 替代docs/guides/reactivity.md、docs/guides/coming_from/jupyter.md
Streamlit创建与显示分离的 UI 写法、最小化重跑docs/guides/coming_from/streamlit.md、docs/api/inputs/index.md
Jupytext.py/.md原生存储、marimo convert/marimo exportdocs/guides/coming_from/jupytext.md
Papermillmo.cli_args/mo.query_paramsCell.run/app.rundocs/api/cli_args.md、docs/api/cell.md、docs/guides/coming_from/papermill.md

所有迁移示例都可在仓库 examples 目录中找到对应的可运行范例;转换与执行命令均由 marimo/_cli/cli.py 中的convertexporteditrun子命令提供。建议迁移时先在本地用marimo edit打开一个转换后的 notebook,感受响应式执行与"notebook 即应用"的工作流差异。

【免费下载链接】marimoA reactive notebook for Python — run reproducible experiments, query with SQL, execute as a script, deploy as an app, and version with git. Stored as pure Python. All in a modern, AI-native editor.项目地址: https://gitcode.com/GitHub_Trending/ma/marimo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询