ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

从 Jupyter 迁移到 marimo:执行模型、变量作用域与文件格式的完整适配指南

从 Jupyter 迁移到 marimo:执行模型、变量作用域与文件格式的完整适配指南 从 Jupyter 迁移到 marimo执行模型、变量作用域与文件格式的完整适配指南【免费下载链接】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/marimomarimo 是面向 Python 的响应式reactive笔记本它把每个单元格编译成基于变量声明与引用的依赖图运行一个单元格时会自动运行所有读取其变量的单元格从而彻底消除 Jupyter 中常见的隐藏状态hidden state问题。本指南以 docs/guides/coming_from/jupyter.md 为骨架面向从 Jupyter 迁移过来的开发者系统讲解 marimo 的执行模型、变量重定义约束、纯 Python 文件格式、marimo convert与marimo export双向转换命令以及 IPython 魔法命令的替代方案帮助你快速适应新的编程心智模型。为什么 marimo 与 Jupyter 的执行方式不同Jupyter 笔记本本质是一个REPL你一条条地执行代码块Jupyter 并不理解不同代码块之间的依赖关系。这带来两个常见问题你可能乱序执行单元格你可能运行或删除了某个单元格却忘了重新运行依赖其变量的下游单元格。由此Jupyter 笔记本很容易累积隐藏状态以及隐藏的 bug。正是因为这种无序执行与不完整重跑Jupyter 笔记本长期面临可复现性危机——原文档指出GitHub 上超过三分之一的 Jupyter 笔记本无法复现。marimo 则不同它在不运行代码的前提下静态分析每个单元格参见 docs/guides/reactivity.md提取两类信息references单元格读取但未定义的全局变量definitions单元格定义的全局变量。然后 marimo 在单元格之间构建一张有向无环图DAG如果某个单元格引用了另一个单元格的 definition二者之间就有一条边。运行一个单元格时它的所有后代单元格都会被标记为待执行。运行时规则Runtime Rule运行某个单元格时marimo 会自动运行所有引用了该单元格所定义的全局变量的其他单元格。这种机制让代码与输出始终保持一致也让笔记本能被复用为应用app和脚本script。从源码结构看这一静态分析逻辑集中在 marimo/_ast 目录如visitor.py、variables.py、compiler.py编译阶段将单元格源代码解析为变量依赖关系而运行时的执行编排位于 marimo/_runtime。删除一个单元格时会同时把它的全局变量从程序内存中删除引用这些变量的单元格会被自动重跑或标记为 stale取决于运行时配置这正是 marimo 消除传统笔记本常见 bug 的方式。配置 marimo 的运行时Runtime默认行为运行一个单元格自动带动依赖单元格可能让你一时难以适应尤其是当部分单元格很昂贵时。marimo 允许你通过笔记本设置菜单配置运行时行为详见 docs/guides/configuration/runtime_configuration.mdOn startup控制用marimo edit打开笔记本时是否在启动时自动运行marimo run以应用方式分享时该设置不生效On cell change默认automatic自动运行依赖单元格可改为lazy——运行单元格时只把受影响的依赖单元格标记为stale不会自动运行。当你运行一个有 stale 祖先的单元格时那些祖先也会先运行以确保你不会用到过期输入你可以随时点击运行按钮或使用快捷键一次性运行所有 stale 单元格Cache cells通过pyproject.toml的[tool.marimo.runtime] cache_cells true让 marimo 尝试缓存笔记本中每个已执行的单元格区别于默认仅缓存显式用mo.cache/mo.persistent_cache装饰的函数详见 docs/api/caching.mdOn module change模块自动重载autorun 或 lazy 两种模式编辑 Python 模块时自动重跑受影响的单元格。即使在关闭自动运行的情况下marimo 仍会跨单元格追踪依赖把已运行单元格的依赖者标记为 stale你只需要点击一个按钮就能运行所有 stale 单元格让笔记本重新回到最新状态。用mo.stop停止执行mo.stop用于在满足某个条件时中止当前单元格的执行# 如果 condition 为 Truemo.stop() 返回后单元格停止执行 mo.stop(condition) # 如果 condition 为 True下面这行不会被调用 expensive_function_call()mo.stop常与mo.ui.run_button()搭配为昂贵的单元格增加按钮门槛app.cell def __(): run_button mo.ui.run_button() run_button return app.cell def __(): mo.stop(not run_button.value, mo.md(Click to run this cell)) mo.md(You clicked the button! ) return只有当用户按下按钮后第二个单元格才会真正执行。处理昂贵笔记本的其他手段关于适配 marimo 执行模型的更多技巧可参考 docs/guides/expensive_notebooks.md其中还包含禁用单个单元格disabled cells、用del释放内存、用mo.cache/mo.persistent_cache缓存昂贵计算、以及用mo.lazy惰性渲染昂贵 UI 等方案。变量重定义约束与适配建议marimo 会把笔记本单元格编译成一张以变量声明和引用连接的有向图并复用这张图把笔记本当作脚本或应用来运行。为了让编译可行同一个全局变量不能被多个单元格定义——否则 marimo 无法确定单元格的执行顺序。原文档给出的三条适配建议尽可能把代码封装进函数减少全局变量的数量用下划线前缀标记临时变量_my_temporary这样的变量对单元格是局部的——其他单元格无法读取它不同单元格也可以复用相同的局部变量名。注意导入名也是变量import numpy as _np同样只在本单元格内可见如果导入的符号本身以下划线开头且要跨单元格使用应给它一个不带下划线的别名如from ibis import _ as d在定义变量的单元格中就地修改它。DataFrame 的常见误区如果你习惯在多个单元格中反复重定义同一个df这在 marimo 中行不通。正确做法是把单元格合并成一个不要这样做df pd.DataFrame({my_column: [1, 2]})df[another_column] [3, 4]应该这样做df pd.DataFrame({my_column: [1, 2]}) df[another_column] [3, 4]如果确实需要跨多个单元格变换 DataFrame可以给 DataFrame 起一个别名df pd.DataFrame({my_column: [1, 2]})augmented_df df augmented_df[another_column] [3, 4]背后原因在 docs/guides/reactivity.md 中有更完整的说明marimo不追踪对对象的可变修改如my_list.append(42)、df[col] ...、obj.attr 42都不会触发依赖单元格的重跑因为可靠地追踪 Python 中的可变修改是不可能的。因此推荐创建新变量而不是修改旧变量的函数式风格。如果你发现自己反复复制粘贴同一段绘图代码可以试试用函数封装临时变量def _(): import matplotlib.pyplot as plt fig, ax plt.subplots() ax.plot([1, 2]) return ax _()这样plt、fig、ax都不会进入全局命名空间。另外由于变量名必须唯一不能用重新赋值来释放内存需要改用函数封装或del操作符参见 docs/guides/expensive_notebooks.md。marimo 的文件格式纯 Python 而非 JSONmarimo 用Python而不是 JSON 存储笔记本。这意味着你可以用 git 对笔记本做版本管理把笔记本当作脚本执行python notebook.py可通过sys.argv接收参数把具名单元格导入到其他 Python 文件中from my_notebook import my_function。代价是笔记本的输出如图表不会保存在文件中。存储笔记本输出如果你希望保留可视化的工作记录可以开启Auto-download as HTML/IPYNB设置位于笔记本设置中参见 docs/guides/configuration/index.md。开启后marimo 会周期性地把笔记本快照成 HTML 或 ipynb保存到笔记本目录下的__marimo__文件夹中自动快照行为详见 docs/guides/exporting/jupyter_notebook.md 与 docs/guides/exporting/static_html.md。你也可以随时用 CLI 的marimo export命令手动导出 ipynb。在 GitHub 上预览笔记本输出把导出的 ipynb 文件一并提交到版本控制即可在 GitHub 上直接查看笔记本输出也可以安装marimo glance浏览器扩展Chrome / Firefox 均有在 GitHub 页面上渲染笔记本的实时交互式预览。该扩展通过 WebAssembly 渲染笔记本因此对廉价且自包含的笔记本效果最好并非所有笔记本都能工作。把 Jupyter 笔记本转换成 marimo 笔记本在命令行执行marimo convert your_notebook.ipynb -o your_notebook.py从 marimo/_cli/convert/commands.py 的源码可以看到该命令的更多行为支持.ipynb本地或 GitHub 托管的、.md/.qmd含{python}代码围栏与.py三种输入转换 Jupyter 笔记本时会剥离输出不指定-o时转换结果直接打印到 stdout如果输入已经是合法的 marimo 笔记本命令会提示 File is already a valid marimo notebook. 并直接返回可以用全局 flag 组合调用例如marimo -q -y convert script.py -o your_nb.py以静默输出并自动接受所有提示转换完成后marimo edit your_nb.py即可打开编辑。把 Python 脚本转换成 marimo 笔记本marimo convert your_script.py -o your_notebook.py支持两类脚本py:percent 格式如果脚本使用了# %%单元格标记marimo 会把它转换成多单元格笔记本需要安装 jupytext。从 marimo/_convert/non_marimo_python_script.py 的实现可以看到py:percent 的转换是通过jupytext.reads(source, fmtpy:percent)完成的缺少 jupytext 时CLI 会抛出专门的缺失依赖错误并给出重跑命令普通 Python 脚本没有单元格标记的脚本会被转换成单单元格笔记本。使用 uv 进行 py:percent 转换时可以把 jupytext 作为临时依赖注入uvx --withjupytext marimo convert your_script.py -o your_notebook.py注意由于 marimo 的响应式执行与传统笔记本不同转换后可能需要重构那些在多个单元格中修改同一变量的代码例如在多个单元格中修改 DataFrame否则可能产生非预期行为。把 marimo 笔记本导出为 Jupyter 笔记本marimo export ipynb notebook.py -o notebook.ipynb从 marimo/_cli/export/commands.py 可以看出该命令支持更丰富的选项选项说明--sorttopological默认按拓扑序导出单元格保证 ipynb 可以自上而下顺序运行--sorttop-down则保持与 marimo 笔记本一致的书页顺序--include-outputs运行笔记本并把输出写入导出的 ipynb配合--sandbox可在沙箱中运行--watch监听文件变化修改后自动重新导出-f, --force输出文件已存在时强制覆盖-o输出路径缺省时打印到 stdout该命令需要安装nbformat源码中通过DependencyManager.nbformat.require(...)检查缺失时会给出明确提示。导出后你就可以进入 Jupyter 庞大的导出生态nbconvert、Quarto、JupyterBook 等。需要提醒的是部分 marimo 库函数包括 UI 元素在 Jupyter 笔记本中无法工作。你随时可以再用marimo convert notebook.ipynb -o notebook.py把 ipynb 转回 marimo 笔记本。魔法命令Magic Commands的替代方案marimo 笔记本就是纯 Python这提升了可维护性因此不支持 IPython 魔法命令也不支持!前缀的 shell 命令。下面是原文档给出的完整替代对照表Magic Command替代方案%cdos.chdir()也可参考mo.notebook_dir()%clear右键或切换单元格操作cell actions%debugPython 内置调试器breakpoint()%envos.environ%load不适用——使用 Python import%load_ext不适用%autoreloadmarimo 的模块自动重载%matplotlibmarimo 自动显示图表%pwdos.getcwd()%pipmarimo 的内置包管理%who_lsdir()、globals()、mo.refs()、mo.defs()%systemsubprocess.run()%%timetime.perf_counter()或 Python 的 timeit 模块%%timeitPython 的 timeit 模块%%writefilewith open(file.txt, w) as f: f.write(...)%%capturemo.capture_stdout()、mo.capture_stderr()%%htmlmo.Html()或mo.md()%%latexmo.md(r$$...$$)用 subprocess.run 执行控制台命令import subprocess # 等价于执行: ls -l subprocess.run([ls, -l])用 marimo 的包管理器安装依赖使用 marimo 的包管理侧边栏面板即可把包安装到当前环境不需要%pip。详细用法见包管理指南。迁移小贴士总结接受响应式执行运行一个单元格会级联运行其依赖单元格。不习惯时先把运行时切到 lazy 模式用运行 stale 单元格按钮手动控制用mo.stopmo.ui.run_button给昂贵单元格加保险全局变量唯一多用函数封装、下划线局部变量把可变修改放到定义单元格内完成文件即代码笔记本是纯 Python用 git 管理需要输出记录就开启__marimo__自动快照需要喂给 Jupyter 生态就用marimo export ipynb用marimo convert一键迁移ipynb 与 py:percent 脚本都能转换py:percent 需要 jupytext可用uvx --withjupytext临时注入。原文档还附带了一个交互式指南——它本身就是一个 marimo 笔记本可以在浏览器中实际体验上述所有概念作为上手练习的补充材料。【免费下载链接】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),仅供参考
返回列表