marimo 函数复用机制详解:用 setup cell 与 @app.function 将笔记本中的函数与类导出为可导入模块

发布时间:2026/9/13 22:50:02
marimo 函数复用机制详解:用 setup cell 与 @app.function 将笔记本中的函数与类导出为可导入模块
marimo 函数复用机制详解用 setup cell 与 app.function 将笔记本中的函数与类导出为可导入模块【免费下载链接】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 中可复用顶层定义reusable top-level definitions的完整机制如何创建 setup cell、用app.function/app.class_definition把笔记本中的函数与类固化为文件顶层定义并配合源码分析说明 marimo 判定一个 cell 能否成为顶层定义的具体规则单一定义、依赖仅限 setup cell 与顶层符号。读完之后你可以把笔记本当作普通 Python 模块在任意脚本或其他笔记本中以标准import语法导入其中的函数与类让实验代码可复用、可测试并能在任意文本编辑器中直接维护。核心思想笔记本即纯 Python 模块marimo 的笔记本文件本身就是一个合法的 Python 脚本marimo.App()对象 一系列 cell 装饰器。对于函数或类marimo 允许把它们序列化到 .py 文件的顶层——即不包在 cell 函数里而是作为模块级def/class语句存在。这样当别的 Python 文件执行from my_notebook import xxx时导入的是真正的 Python 函数/类对象而不是 cell 包装器。要让一个函数或类被保存在笔记本文件的顶层必须同时满足以下两条准则原文档 Importing functions and classes defined in notebooks 中给出的判定标准该 cell 只能定义一个函数或类Cell must contain exactly one function definition函数或类中引用的符号只能来自 setup cell 的定义或其他已知的顶层符号其他顶层函数/类、内置名。这两条准则在源码中有精确实现。marimo/_ast/toplevel.py定义了TopLevelExtraction与TopLevelStatus在保存笔记本时对每个 cell 执行静态检查不满足条件的 cell 会被降级demote回普通 cell并且前端 cell 右下角的标记会显示具体原因。源码中列举的全部不通过原因如下marimo/_ast/toplevel.py判定提示含义Cell must contain exactly one function definitioncell 内不止一个定义无法整体提升为顶层This function depends on variables defined by other cells: ...函数依赖了其他普通 cell 的变量需把这些变量挪进 setup cellFunction contains references to variables ... which were unable to become reusable.函数引用了同样无法变成顶层的变量闭包依赖链断裂Reusable definitions cannot be named app, __name__ or __generated_with顶层定义不能占用这些保留名Definitions starting with _ are local to a cell.以下划线开头的变量按约定是 cell 局部变量不能复用Signature and decorators depend on ... defined out of correct cell order装饰器/签名引用的符号定义顺序不符合要求Cell cannot contain non-indented trailing comments.单元格末尾存在非缩进尾注释无法无损往返序列化这个提示集合比文档正文描述得更完整它解释了编辑器右下角为什么这个函数不可复用的全部文案来源。一个典型示例定义一个工具函数和一个类并标记为顶层来自原文档app.function def my_utility_function(x): return x * 2 app.class_definition class DataProcessor: def __init__(self, data): self.data data def process(self): return [x * 2 for x in self.data]在另一个脚本或笔记本中即可直接用标准 Python 语法导入from my_notebook import my_utility_function, DataProcessor创建可复用的顶层函数三步流程1. 创建 setup cell先为函数/类所需的导入建立setup cell。在编辑器中打开笔记本菜单选择 Add setup cell。setup cell 保证在任何其他 cell 之前执行也是顶层定义被允许引用的唯一普通 cell来源import numpy as np以直接编辑 .py 文件的视角setup cell 写作with app.setup: import numpy as np从源码看app.setup是一个属性返回_SetupContext上下文管理器marimo/_ast/app.py。进入该上下文时_SetupContext.__enter__会做两件事marimo/_ast/app.py拒绝在 setup cell 中重新定义app本身拒绝 setup cell 引用除内置名BUILTINS之外的任何变量——即 setup cell 必须是自包含的导入块。上下文退出时__exit__收集本次新增的定义self._glbls这些名字随后成为顶层函数被允许引用的符号集合。这也解释了文档中的提示函数只能引用 setup cell 中定义的符号否则无法被序列化到顶层。此外setup cell 还支持with app.setup(hide_codeTrue):的形式来在界面中隐藏其代码。2. 定义你的函数在一个 cell 中定义单个函数。当满足顶层准则时cell 右下角会出现可复用标记对应前端组件 frontend/src/components/editor/notebook-cell.tsx 中渲染 reusable 提示的位置若不满足该标记会附带原因说明即上一节列出的TopLevelInvalidHints。with app.setup: import numpy as np app.function def calculate_statistics(data): Calculate basic statistics for a dataset return { mean: np.mean(data), median: np.median(data), std: np.std(data) }底层机制app.function与app.class_definition装饰器。文档指出marimo 在底层用app.function装饰顶层函数、用app.class_definition装饰顶层类如果你直接用文本编辑器编辑笔记本文件可以手写这两个装饰器来声明自己的顶层函数。App.function与App.class_definition的实现marimo/_ast/app.py都是转调CellManager.cell_decorator(..., top_levelTrue)两者均可带参调用如app.function(disabledTrue)也可不带括号。关键在于top_levelTrue分支marimo/_ast/cell_manager.py装饰后返回的是原函数/类对象本身Top level functions are exposed as the function itself因此模块导入方拿到的就是纯函数cell 仅作为执行图中的注册记录存在。若被装饰的对象不是合法函数/类例如常量赋值顶层路径会静默放行原对象而不是报错保证静态解析能加载的笔记本导入时也不会失败。保存笔记本时代码生成端用to_top_functiondef把满足条件的 cell 还原为文件顶层代码类生成app.class_definition装饰器、函数生成app.function装饰器marimo/_ast/codegen.py普通 cell 则生成app.cell形式。序列化前后由safe_serialize_cell做语法校验兜底确保绝不生成非法代码marimo/_ast/codegen.py。判定一个 cell 能否成为顶层核心逻辑在TopLevelStatus.updatemarimo/_ast/toplevel.py先取 cell 的toplevel_variable必须是唯一、非临时的定义再检查未约束引用是否全部落在allowed_refssetup cell 定义 内置名 其他顶层名之内TopLevelExtraction._resolve_dependencies还会递归解析依赖把引用了尚未确定身份的其他 cell 的函数标记为 unresolved待整体解析后再决定提升或降级——这就是顶层符号可以互相引用能成立的原因。相关测试可参考 tests/_ast/test_toplevel.py 中对app.function各类场景的覆盖例如引用外部 SQL 表的函数仍保持 TOPLEVEL 状态。3. 在其他 Python 文件中导入满足条件后函数就挂在模块顶层可被任意脚本直接导入调用# In another_script.py from my_notebook import calculate_statistics data [1, 2, 3, 4, 5] stats calculate_statistics(data) print(stats)由于导入路径与普通模块完全一致第三方 IDE、类型检查器、测试框架都能直接工作这正是文档开头所说的让代码可复用、可测试、可在任意编辑器中维护的实现方式。与 app.run() 的配合以脚本方式驱动整个笔记本除了导入单个函数你还可以导入整个app对象并程序化运行笔记本app.run()的定义与示例见 marimo/_ast/app.pyfrom my_notebook import app outputs, defs app.run() # defs 中包含笔记本运行后定义的所有变量值app.run(defs{...})还可以覆盖指定 cell 的定义值覆盖的 cell 不再执行依赖它的 cell 使用你提供的值适合把笔记本作为参数化实验组件复用。注意defs不能覆盖 setup cell 中的定义否则会抛出TypeError见 marimo/_ast/app.py。最佳实践继承原文档并补充说明把广泛使用的导入放进 setup cell——这是顶层函数引用符号的唯一合法通道限制函数依赖只依赖 setup cell 引用或其他顶层声明若函数需要数据DataFrame 等不要引用某个 cell 算出来的变量而是让函数接收参数使用描述性命名顶层名字就是模块导出的 API 名添加 docstring文档字符串随函数进入导入方是模块级文档的直接载体利用顶层符号间的相互引用原文档 tip顶层函数可以引用其他顶层函数/常量。源码层面TopLevelExtraction以拓扑序做依赖解析marimo/_ast/toplevel.py因此这种函数调用另一个函数的结构会被整体提升为顶层。局限性原文档列出的限制结合源码逐条说明函数不能依赖普通 cell 中定义的变量。判定逻辑见TopLevelStatus.update中的HINT_HAS_REFS分支依赖其他 cell 变量时cell 会被降级为普通app.cell并提示move these variables to the setup cellmarimo/_ast/toplevel.py。顶层函数之间不允许循环依赖——与其他 cell 一样循环依赖会被数据流图拒绝CycleErrormarimo/_ast/app.py。注意源码注释指出一个细节以库形式纯 Python import使用时循环调用在原始 Python 语义下仍可运行只有在 marimo 直接运行该 app 时才会报错marimo/_ast/toplevel.py。局部变量不可复用以_开头的定义被 visitor 归为 temporaryTopLevelStatus会直接以HINT_NO_PRIVATES降级marimo/_ast/toplevel.py。markdown 格式的笔记本无法导出函数marimo 的 markdown 笔记本格式不支持顶层函数导出原文档引用的 markdown 导出说明。由源码结构看还有两条文档未明说但实际存在的约束顶层定义不能命名为app、__name__、__generated_withcell 末尾不能出现非缩进尾注释marimo/_ast/toplevel.py否则同样会被降级为普通 cell。延伸阅读marimo 纯 Python 文件格式、用第三方编辑器编辑笔记本的完整说明docs/guides/editor_features/watching.md本文讨论的判定与序列化实现marimo/_ast/toplevel.py、marimo/_ast/codegen.py装饰器与app.setup上下文实现marimo/_ast/app.py顶层定义的回归测试tests/_ast/test_toplevel.py【免费下载链接】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),仅供参考