Marimo 笔记本导出为纯 Python 脚本(Flat Script)完整指南
【免费下载链接】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 反应式笔记本导出为扁平的纯 Python 脚本文件,覆盖编辑器菜单操作、marimo export script命令行用法及其全部参数、导出产物的内部结构与排序原理,以及 top-level await 等边界限制。读完你将能够把任意 marimo 笔记本一键转换为可复用、可版本化、可在任意 Python 环境中运行的普通.py文件。
什么是 Flat Script 导出
marimo 笔记本本身以纯 Python 文件(.py)存储,其内部结构是带有# %%单元格分隔标记与元数据头部的 marimo 格式。而Flat Script(扁平脚本)导出生成的是另一种形态的产物:它把笔记本中所有单元格的代码按照拓扑顺序(topological order)拼接成一个自上而下顺序执行的普通 Python 脚本,不再包含 marimo 专用的单元格包装逻辑,可以像任何普通 Python 脚本一样直接运行、导入和提交到 git。
两者本质区别在于:
- marimo 笔记本文件:以
# %%标记单元格边界,依赖 marimo 运行时按依赖图执行,可被marimo edit重新打开; - 导出的扁平脚本:所有代码按依赖关系拍平成顺序执行流,仅依赖标准 Python 解释器,不依赖 marimo 运行时。
官方导出命令对它的描述是"Export a marimo notebook as a flat script, in topological order"(见 marimo/_cli/export/commands.py 中的script命令定义),这正是理解该功能的关键。
从 marimo 编辑器导出
在 marimo 编辑器中,无需记忆任何命令即可完成导出:
- 打开你的笔记本(
marimo edit notebook.py); - 点击界面右上角的notebook 菜单;
- 选择"Export…";
- 在格式中选择"Python",子格式选择"Flat script";
- 浏览器即会下载生成好的
.script.py文件。
该导出路径与命令行导出共用同一套底层实现,导出的产物完全一致,因此下文对命令行的剖析同样适用于编辑器导出。
从命令行导出
命令行导出的基本用法:
marimo export script notebook.py -o notebook.script.pynotebook.py:要导出的 marimo 笔记本路径;-o notebook.script.py:输出文件路径。若省略-o,脚本内容将直接打印到 stdout(方便管道处理或重定向)。
marimo export script还支持以下参数(详见 marimo/_cli/export/commands.py):
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
-o, --output <path> | 路径 | 无(打印到 stdout) | 导出脚本的输出文件路径 |
--watch / --no-watch | 布尔 | False | 监听笔记本文件变化,修改后自动重新生成脚本 |
--sandbox / --no-sandbox | 布尔 | 未指定 | 是否在隔离的沙箱虚拟环境中执行导出(uv 沙箱) |
-f, --force | 布尔 | False | 输出文件已存在时强制覆盖 |
name | 路径(必填) | — | 待导出的笔记本文件,必须是存在的文件 |
监听模式(--watch)
在开发迭代过程中,可以开启监听模式,让导出脚本在每次保存笔记本时自动重新生成:
marimo export script notebook.py -o notebook.script.py --watch该功能由watch_and_export实现(见 marimo/_cli/export/commands.py):它使用文件监视器监听笔记本文件的修改事件,一旦发生变化便重新执行导出回调并覆写输出文件。相关行为在 tests/_cli/test_cli_export.py 的test_export_watch_script中有自动化测试覆盖。
沙箱导出(--sandbox)
如果笔记本在顶部声明了 PEP 723 内联依赖(# /// script依赖块),--sandbox选项会创建一个隔离的 uv 虚拟环境来执行导出,确保依赖可用且不污染当前环境。导出测试test_export_script_with_inline_deps验证了这种场景下生成的脚本会保留原始的 PEP 723# /// script头部以及polars等内联依赖声明,使导出产物仍然自包含、可直接运行。
导出产物的内部结构
在 marimo/_convert/script.py 的convert_from_ir_to_script函数中,可以看到导出脚本的完整生成逻辑。一个典型的导出脚本结构如下:
# 原始文件头部(若有):PEP 723 依赖块、版权注释等 __generated_with = "0.x.x" # 生成时的 marimo 版本号 # %% # 第 1 个单元格的代码(拓扑顺序) # %% # 第 2 个单元格的代码 ...具体生成规则包括:
- 头部保留:Python 源笔记本中的原始头部文本(PEP 723 依赖块、版权注释)会被提取并置于导出脚本顶部;若源是 Markdown 笔记本,则会解析其 YAML frontmatter,恢复其中的
pyproject/header字段(见_header_for_script)。 - 版本标记:脚本第二行写入
__generated_with = "<版本号>",标识该脚本由哪个 marimo 版本生成,便于追踪与排障。 - 单元格分隔:每个单元格以
# %%注释行分隔(marimo 的标准单元格边界标记),与 marimo 原生文件格式保持一致。 - 拓扑排序:单元格代码不是按书写顺序拼接,而是依据单元格间的变量依赖关系图进行拓扑排序,保证脚本从上到下顺序执行时每个单元格引用的变量都已定义。这一点在测试 tests/_server/api/endpoints/test_export.py 的
test_export_script_uses_topological_order中有直接验证。
重要限制:不支持 top-level await
导出为扁平脚本不支持顶层 await(top-level await)。如果笔记本中含有await表达式(例如await asyncio.sleep(1)或await some_async_fn()),导出会失败并抛出UnsupportedAsyncCodeError,错误信息为 "Cannot export a notebook with async code to a flat script"(见 marimo/_convert/script.py)。
原因在于:扁平脚本是纯同步的普通 Python 文件,Python 语言本身不允许在模块顶层使用await;而 marimo 笔记本依赖其异步运行时才支持此能力。
应对方案:
- 若笔记本确实包含顶层 await,可以跳过导出,直接用 Python 解释器执行笔记本本身:
python notebook.pymarimo 笔记本原生支持以脚本方式运行(见 运行脚本指南),此时异步能力由 marimo 运行时接管;
- 或者将
await封装进asyncio.run()等同步包装中,使所有单元格均为同步代码后再导出。
这一限制在命令行与编辑器两种导出方式下均存在,且由测试test_export_script_async与test_export_script_rejects_async_notebook双重验证:异步笔记本导出会以退出码 1 失败并输出上述错误信息。
其他边界情况与错误处理
依据测试 tests/_cli/test_cli_export.py 中TestExportScript的覆盖,还需了解以下行为:
| 场景 | 行为 |
|---|---|
| 普通笔记本 | 导出成功,产物按拓扑顺序排列 |
| 含顶层 await 的笔记本 | 导出失败,报Cannot export a notebook with async code to a flat script |
| 含同名变量重复定义的笔记本 | 导出失败,报 "multiple definitions of the name x"(MultipleDefinitionError) |
| 含运行错误的笔记本 | 导出仍然成功——导出只负责拼接代码,不执行代码,因此单元格内的语法/运行时错误会被原样带入脚本,便于在脚本中复现排查 |
| 含 PEP 723 内联依赖的笔记本 | 导出成功,且保留# /// script依赖头部 |
特别注意第 4 点:marimo export script是纯静态转换,不会执行笔记本代码(这一点与marimo export html等需要运行笔记本的导出不同,后者会经过会话执行流程,见 marimo/_export/file.py 中export_html与export_script的实现差异)。因此它速度快、无副作用,也正因如此代码中的错误不会被拦截,而是在脚本实际运行时才暴露。
复用导出脚本
导出得到的扁平脚本可以被当作普通 Python 模块复用:
- 作为脚本运行:
python notebook.script.py,或通过marimo run notebook.script.py以应用形式启动(不过此时文件已非 marimo 笔记本格式,直接python运行即可满足大多数场景); - 作为模块导入:在其他代码中
import notebook_script,复用其中定义的函数与变量; - 纳入 git 版本控制:扁平脚本是纯文本,diff 清晰,非常适合加入 CI 流程进行自动化测试或定时任务。
关于脚本运行与模块复用的完整进阶技巧,参见仓库中的 以脚本方式运行笔记本 与 复用笔记本中的函数 两篇指南。
小结
marimo export script(或编辑器中的 Export → Python → Flat script)将反应式笔记本按拓扑顺序拍平成标准的纯 Python 脚本:头部与内联依赖保留、版本号标记、# %%分隔清晰、纯静态转换不执行代码。唯一需要回避的坑是顶层await,遇到时可改用python notebook.py直接运行笔记本。生成的脚本可无缝融入既有 Python 工程,作为脚本、模块或 CI 产物使用,是 marimo 笔记本"一次编写、随处运行"能力的关键一环。
进一步阅读(位于同一导出指南目录下):
- 导出 Markdown:docs/guides/exporting/markdown.md
- 导出 Jupyter Notebook:docs/guides/exporting/jupyter_notebook.md
- 导出静态 HTML 与 WebAssembly HTML:docs/guides/exporting/static_html.md、docs/guides/exporting/webassembly_html.md
- 导出 PDF:docs/guides/exporting/pdf.md
- 导出指南总览:docs/guides/exporting/index.md
【免费下载链接】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),仅供参考