marimo-notebook
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNotes for marimo Notebooks
marimo笔记本编写注意事项
Running Marimo Notebooks
运行marimo笔记本
bash
undefinedbash
undefinedRun as script (non-interactive, for testing)
以脚本模式运行(非交互式,用于测试)
uv run <notebook.py>
uv run <notebook.py>
Run interactively in browser
在浏览器中交互式运行
uv run marimo run <notebook.py>
uv run marimo run <notebook.py>
Edit interactively
交互式编辑
uv run marimo edit <notebook.py>
undefineduv run marimo edit <notebook.py>
undefinedScript Mode Detection
脚本模式检测
Use to detect CLI vs interactive:
mo.app_meta().mode == "script"python
@app.cell
def _(mo):
is_script_mode = mo.app_meta().mode == "script"
return (is_script_mode,)使用来检测是CLI模式还是交互式模式:
mo.app_meta().mode == "script"python
@app.cell
def _(mo):
is_script_mode = mo.app_meta().mode == "script"
return (is_script_mode,)Key Principle: Keep It Simple
核心原则:保持简洁
Show all UI elements always. Only change the data source in script mode.
- Sliders, buttons, widgets should always be created and displayed
- In script mode, just use synthetic/default data instead of waiting for user input
- Don't wrap everything in conditionals
if not is_script_mode - Don't use try/except for normal control flow
始终显示所有UI元素。仅在脚本模式下更改数据源。
- 滑块、按钮、小部件应始终创建并显示
- 在脚本模式下,只需使用模拟/默认数据,无需等待用户输入
- 不要将所有内容都包裹在条件判断中
if not is_script_mode - 不要在常规控制流中使用try/except
Good Pattern
良好实践
python
undefinedpython
undefinedAlways show the widget
始终显示小部件
@app.cell
def _(ScatterWidget, mo):
scatter_widget = mo.ui.anywidget(ScatterWidget())
scatter_widget
return (scatter_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
@app.cell
def _(is_script_mode, make_moons, scatter_widget, np, torch):
if is_script_mode:
# 使用模拟数据进行测试
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:
# 在交互式模式下使用小部件数据
X, y = scatter_widget.widget.data_as_X_y
# ... 处理数据 ...
return X_data, y_data, data_error
Always show sliders - use their .value in both modes
始终显示滑块 - 在两种模式下都使用其.value属性
@app.cell
def _(mo):
lr_slider = mo.ui.slider(start=0.001, stop=0.1, value=0.01)
lr_slider
return (lr_slider,)
@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,)
undefined@app.cell
def _(is_script_mode, train_button, lr_slider, run_training, X_data, y_data):
if is_script_mode:
# 使用滑块默认值自动运行
results = run_training(X_data, y_data, lr=lr_slider.value)
else:
# 等待按钮点击
if train_button.value:
results = run_training(X_data, y_data, lr=lr_slider.value)
return (results,)
undefinedDon't Guard Cells with if
Statements
if不要用if
语句包裹单元格
ifMarimo's reactivity means cells only run when their dependencies are ready. Don't add unnecessary guards:
python
undefinedMarimo的响应式特性意味着单元格仅在其依赖项就绪时才会运行。不要添加不必要的判断:
python
undefinedBAD - the if statement prevents the chart from showing
错误写法 - if语句会阻止图表显示
@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
@app.cell
def _(plt, training_results):
if training_results: # 错误 - 不要这样做
fig, ax = plt.subplots()
ax.plot(training_results['losses'])
fig
return
GOOD - let marimo handle the dependency
正确写法 - 让marimo处理依赖关系
@app.cell
def _(plt, training_results):
fig, ax = plt.subplots()
ax.plot(training_results['losses'])
fig
return
The cell won't run until `training_results` has a value anyway.@app.cell
def _(plt, training_results):
fig, ax = plt.subplots()
ax.plot(training_results['losses'])
fig
return
在`training_results`有值之前,单元格不会运行。Don't Use try/except for Control Flow
不要在控制流中使用try/except
Don't wrap code in try/except blocks unless you're handling a specific, expected exception. Let errors surface naturally.
python
undefined除非你要处理特定的、可预期的异常,否则不要将代码包裹在try/except块中。让错误自然暴露。
python
undefinedBAD - hiding errors behind try/except
错误写法 - 用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}"
@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)
# ...
Only use try/except when:
- You're handling a specific, known exception type
- The exception is expected in normal operation (e.g., file not found)
- You have a meaningful recovery action@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:
- 你要处理特定的、已知的异常类型
- 该异常在正常操作中是可预期的(例如,文件未找到)
- 你有有意义的恢复措施Cell Output Rendering
单元格输出渲染
Marimo only renders the final expression of a cell. Indented or conditional expressions won't render:
python
undefinedMarimo仅渲染单元格的最终表达式。缩进或条件中的表达式不会被渲染:
python
undefinedBAD - indented expression won't render
错误写法 - 缩进的表达式不会被渲染
@app.cell
def _(mo, condition):
if condition:
mo.md("This won't show!") # WRONG - indented
return
@app.cell
def _(mo, condition):
if condition:
mo.md("这不会显示!") # 错误 - 缩进了
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
undefined@app.cell
def _(mo, condition):
result = mo.md("显示内容!") if condition else mo.md("也会显示!")
result # 这会被渲染,因为它是最终表达式
return
undefinedMarimo Variable Naming
Marimo变量命名
Variables in loops that would conflict across cells need underscore prefix:
forpython
undefined在循环中,可能会跨单元格冲突的变量需要以下划线前缀:
forpython
undefinedUse _name, _model to make them cell-private
使用_name, _model使其成为单元格私有变量
for _name, _model in items:
...
undefinedfor _name, _model in items:
...
undefinedPEP 723 Dependencies
PEP 723 依赖声明
python
undefinedpython
undefined/// script
/// script
requires-python = ">=3.12"
requires-python = ">=3.12"
dependencies = [
dependencies = [
"marimo",
"marimo",
"torch>=2.0.0",
"torch>=2.0.0",
]
]
///
///
undefinedundefinedPrefer pathlib over os.path
优先使用pathlib而非os.path
Use for file path operations instead of :
pathlib.Pathos.pathpython
undefined使用进行文件路径操作,而非:
pathlib.Pathos.pathpython
undefinedGOOD - use pathlib
正确写法 - 使用pathlib
from pathlib import Path
data_dir = Path(tempfile.mkdtemp())
parquet_file = data_dir / "data.parquet"
from pathlib import Path
data_dir = Path(tempfile.mkdtemp())
parquet_file = data_dir / "data.parquet"
BAD - avoid os.path
错误写法 - 避免使用os.path
import os
parquet_file = os.path.join(temp_dir, "data.parquet")
undefinedimport os
parquet_file = os.path.join(temp_dir, "data.parquet")
undefinedmarimo check
marimo check命令
When working on a notebook it is important to check if the notebook can run. That's why marimo provides a command that acts as a linter to find common mistakes.
checkbash
uvx marimo check <notebook.py>Make sure these are checked before handing a notebook back to the user.
在开发笔记本时,检查笔记本是否能正常运行非常重要。marimo提供了命令,作为代码检查工具来发现常见错误。
checkbash
uvx marimo check <notebook.py>在将笔记本交付给用户之前,务必执行这些检查。