mcpField
M
marimo-notebook

marimo-notebook

github.com/marimo-team开发1776.0k 次安装10 周前更新
代码仓库

关于 marimo-notebook

面向编写和维护 marimo Notebook 的开发者,提供单元格反应性、运行模式、界面和测试方面的实践指导。还涵盖依赖声明与检查命令。

主要功能

  1. 01单元格依赖与反应性指导
  2. 02交互与脚本模式处理
  3. 03PEP 723 依赖声明
  4. 04marimo check 与测试指导

适用场景

  1. 01创建可交互的 marimo Notebook
  2. 02让 Notebook 支持脚本运行
  3. 03检查 Notebook 常见错误

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/marimo-team/skills --skill marimo-notebook

安装后在 Claude Code 中输入/marimo-notebook确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
ANYWIDGET.md
COLUMNS.md
CONFIGURATION.md
DEPLOYMENT.md
EXPENSIVE.md
EXPORTS.md
PYTEST.md
REACTIVITY.md
SQL.md
STATE.md
TOP-LEVEL-IMPORTS.md
UI.md
WATCHING.md

详细介绍

marimo Notebook 注意事项

marimo 使用 Python 创建 Notebook,而 Jupyter 使用 JSON。以下是一个 Notebook 示例:

# /// script
# dependencies = [
#     "marimo",
#     "numpy==2.4.3",
# ]
# requires-python = ">=3.14"
# ///

import marimo

__generated_with = "0.20.4"
app = marimo.App(width="medium")


@app.cell
def _():
    import marimo as mo
    import numpy as np

    return mo, np


@app.cell
def _():
    print("hello world")
    return


@app.cell
def _(np, slider):
    np.array([1,2,3]) + slider.value
    return


@app.cell
def _(mo):
    slider = mo.ui.slider(1, 10, 1, label="number to add")
    slider
    return (slider,)


@app.cell
def _():
    return


if __name__ == "__main__":
    app.run()

请注意,Notebook 的结构是由表示单元格内容的函数构成的。每个单元格都通过 @app.cell 装饰器定义,函数的输入和输出就是单元格的输入和输出。marimo 通常会自动处理单元格之间的依赖关系。

运行 Marimo Notebook

# Run as script (non-interactive, for testing)
uv run <notebook.py>

# Run interactively in browser
uv run marimo run <notebook.py>

# Edit interactively
uv run marimo edit <notebook.py>

检测脚本模式

使用 mo.app_meta().mode == "script" 来区分命令行与交互模式:

@app.cell
def _(mo):
    is_script_mode = mo.app_meta().mode == "script"
    return (is_script_mode,)

核心原则:保持简单

始终显示所有 UI 元素。 仅在脚本模式下更改数据源。

  • 始终创建并显示滑块、按钮和小组件
  • 在脚本模式下,只需使用合成数据或默认数据,而不是等待用户输入
  • 不要用 if not is_script_mode 条件包裹所有内容
  • 不要将 try/except 用于常规控制流
推荐模式
# Always show the widget
@app.cell
def _(ScatterWidget, mo):
    scatter_widget = mo.ui.anywidget(ScatterWidget())
    scatter_widget
    return (scatter_widget,)

# Only change data source based on mode
@app.cell
def _(is_script_mode, make_moons, scatter_widget, np, torch):
    if is_script_mode:
        # Use synthetic data for testing
        X, y = make_moons(n_samples=200, noise=0.2)
        X_data = torch.tensor(X, dtype=torch.float32)
        y_data = torch.tensor(y)
        data_error = None
    else:
        # Use widget data in interactive mode
        X, y = scatter_widget.widget.data_as_X_y
        # ... process data ...
    return X_data, y_data, data_error

# Always show sliders - use their .value in both modes
@app.cell
def _(mo):
    lr_slider = mo.ui.slider(start=0.001, stop=0.1, value=0.01)
    lr_slider
    return (lr_slider,)

# Auto-run in script mode, wait for button in interactive
@app.cell
def _(is_script_mode, train_button, lr_slider, run_training, X_data, y_data):
    if is_script_mode:
        # Auto-run with slider defaults
        results = run_training(X_data, y_data, lr=lr_slider.value)
    else:
        # Wait for button click
        if train_button.value:
            results = run_training(X_data, y_data, lr=lr_slider.value)
    return (results,)

状态与响应性

对于 99% 的使用场景,单元格之间的变量就能定义 Notebook 的响应性。无需特殊的状态管理。不要跨单元格修改对象(例如 my_list.append());应改为创建新对象。除非需要双向 UI 同步或累积回调状态,否则不要使用 mo.state()。详情请参阅 STATE.md。

不要用 if 语句保护单元格

marimo 的响应性意味着,只有在依赖项就绪时才会运行单元格。不要添加不必要的保护条件:

# BAD - the if statement prevents the chart from showing
@app.cell
def _(plt, training_results):
    if training_results:  # WRONG - don't do this
        fig, ax = plt.subplots()
        ax.plot(training_results['losses'])
        fig
    return

# GOOD - let marimo handle the dependency
@app.cell
def _(plt, training_results):
    fig, ax = plt.subplots()
    ax.plot(training_results['losses'])
    fig
    return

无论如何,只有在 training_results 有值后,该单元格才会运行。

不要将 try/except 用于控制流

除非要处理特定且预期会发生的异常,否则不要用 try/except 块包裹代码。让错误自然显现。

# BAD - hiding errors behind try/except
@app.cell
def _(scatter_widget, np, torch):
    try:
        X, y = scatter_widget.widget.data_as_X_y
        X = np.array(X, dtype=np.float32)
        # ...
    except Exception as e:
        return None, None, f"Error: {e}"

# GOOD - let it fail if something is wrong
@app.cell
def _(scatter_widget, np, torch):
    X, y = scatter_widget.widget.data_as_X_y
    X = np.array(X, dtype=np.float32)
    # ...

仅在以下情况下使用 try/except:

  • 处理特定且已知的异常类型
  • 该异常在正常运行中是预期会发生的(例如,找不到文件)
  • 有明确且有意义的恢复操作

单元格输出渲染

marimo 只会渲染单元格的最后一个表达式。缩进的表达式或条件表达式不会被渲染:

# BAD - indented expression won't render
@app.cell
def _(mo, condition):
    if condition:
        mo.md("This won't show!")  # WRONG - indented
    return

# GOOD - final expression renders
@app.cell
def _(mo, condition):
    result = mo.md("Shown!") if condition else mo.md("Also shown!")
    result  # This renders because it's the final expression
    return

PEP 723 依赖项

通过 marimo edit --sandbox 创建的 Notebook 会自动在文件顶部添加这些依赖项,但创建 Notebook 时也最好确认这些依赖项已存在:

# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "marimo",
#     "torch>=2.0.0",
# ]
# ///

marimo check

编写 Notebook 时,检查其能否正常运行非常重要。因此,marimo 提供了 check 命令,可作为代码检查工具来查找常见错误。

uvx marimo check <notebook.py>

将 Notebook 交还给用户之前,请确保已完成这些检查。

重要提示:你容易过度使用带下划线前缀的变量。最多只应对一两个变量这样处理。对于 marimo,不妨创建新变量,而不是给整个单元格中的变量都加前缀。

API 文档

如果用户明确要求你使用某个 marimo 函数,可以在本地查看文档:

uv --with marimo run python -c "import marimo as mo; help(mo.ui.form)"

测试

默认情况下,marimo 会发现并执行 Notebook 中的测试。 如果存在可选的 pytest 依赖项,marimo 会对完全由测试代码组成的单元格运行 pytest,也就是说,运行名称以 test_ 开头的函数。 如果用户要求你添加测试,请确保添加 pytest 依赖项,并确保有一个单元格只包含测试代码。

有关使用 pytest 进行测试的更多信息,请参阅 PYTEST.md。

添加测试后,可以在命令行中对 Notebook 运行 pytest。

pytest <notebook.py>

附加资源

  • 关于在 width=columns 中运行的 marimo 笔记本,请参阅 SQL.md
  • 关于在 marimo 中使用 SQL,请参阅 SQL.md
  • 关于 marimo 中的 UI 元素,请参阅 UI.md
  • 关于将函数/类公开为顶层导入,请参阅 TOP-LEVEL-IMPORTS.md
  • 关于导出笔记本(PDF、HTML、markdown 等),请参阅 EXPORTS.md
  • 关于状态管理和响应性,请参阅 STATE.md
  • 关于部署 marimo 笔记本,请参阅 DEPLOYMENT.md
  • 关于使用 anywidget 创建自定义交互式小组件,请参阅 ANYWIDGET.md
  • 关于外部编辑和 --watch 模式,请参阅 WATCHING.md
  • 关于开销较大的笔记本(缓存、惰性求值、mo.stop),请参阅 EXPENSIVE.md
  • 关于配置(pyproject.toml、marimo.toml),请参阅 CONFIGURATION.md
  • 关于响应性模型(DAG、变量作用域、变更),请参阅 REACTIVITY.md

评论

支持 Markdown