ARTICLE DETAIL

资讯详情

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

marimo 自定义富显示完全指南:掌握 _display_、_mime_ 与 IPython _repr_*_ 三大显示协议

marimo 自定义富显示完全指南:掌握 _display_、_mime_ 与 IPython _repr_*_ 三大显示协议 marimo 自定义富显示完全指南掌握display、mime与 IPythonrepr*_ 三大显示协议【免费下载链接】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 原生对象list、dict 等、marimo 对象UI 元素以及 matplotlib、seaborn、Plotly、altair、pandas 等库内置了丰富的富显示rich display能力。本文以官方指南 displaying_objects.md 为骨架结合 marimo 格式化协议源码 与测试用例系统讲解如何为自己的对象注册富显示实现_display_()、_mime_()或 IPython 风格_repr_*_()方法并厘清三者之间的优先级与适用场景让库开发者与笔记作者都能产出可直接在 marimo 媒体查看器中渲染的自定义输出。富显示的触发时机与整体机制marimo 会在两种情况下渲染对象的富表示单元格的最后一行表达式一个 cell 执行结束后其最后一个表达式的值会被自动显示通过mo.output.append主动追加输出在单元格执行过程中可以用mo.output.append将任意对象追加为输出同模块还提供mo.output.replace、mo.output.replace_at_index等 API见 marimo/_runtime/output/_output.py。无论哪种方式最终都会走进统一的格式化入口。核心实现位于 marimo/_output/formatting.py 的get_formatter函数L139-L211它先为对象查找合适的 formatter再把对象转换为(mimetype, data)元组交给前端的媒体查看器渲染。若完全找不到 formatter则退化为repr(obj)的纯文本展示。显示优先级源码确认按 get_formatter 的实现顺序三种自定义协议与内置 formatter 的优先级从高到低为_display_()方法拥有最高优先级内置/意见化 formatterbuilt-in / opinionated formatters即 marimo 为 pandas、polars、matplotlib、altair 等类型预注册的格式化器_mime_()方法媒体查看器协议IPython 风格_repr_*_()方法优先级最低。这一优先级同样被测试用例验证在 tests/_output/test_try_format.py 中test_display_protocol与test_mime_protocol分别验证了_display_、_mime_能被正确识别并渲染而test_opinionated_formatter则验证了意见化 formatter 的启用与关闭行为。Option 1实现_display_()方法最便捷如果一个对象实现了_display_()marimo 会调用它并用其返回值作为该对象的输出。这是三种方案中语法最直接的一种class Dice: def _display_(self): import random return fYou rolled {random.randint(0, 7)}_display_的返回值可以是任意 Python 对象——matplotlib 图、DataFrame、列表、mo.Html、mo.ui元素等——marimo 会递归地对返回值再次走一遍格式化流程并尝试渲染。从源码看这一过程位于 formatting.py 的f_mime闭包它先调用obj._display_()拿到返回值再对其调用get_formatter如果返回值也没有 formatter则通过as_html兜底为 HTML 展示。为什么适合库开发者对库开发者而言_display_有一个关键优势在 marimo 中显示对象无需把 marimo 添加为项目依赖。你只要在自己的类上实现一个普通方法marimo 在运行时就能识别并展示它。不过需要注意如果待展示的对象类型 marimo 本身不认识例如你正在构建一个全新的绘图库marimo 还没有为它注册 formatter_display_的返回值最终仍需要落到 marimo 能渲染的类型上。此时就要考虑下面两种方案了。Option 2实现 IPython_repr_*_()方法生态兼容marimo 支持 IPython 的富显示协议即 IPython 官方文档中描述的 custom methods。只要对象实现了下述任一_repr_*_方法marimo 就能渲染它。以下示例借用自 IPython 官方文档class Shout: def __init__(self, text): self.text text def _repr_html_(self): return h1 self.text /h1marimo 支持以下_repr_*_方法_repr_html__repr_mimebundle__repr_svg__repr_json__repr_png__repr_jpeg__repr_markdown__repr_latex__repr_text_注意marimo 目前不处理_repr_mimebundle_返回的可选 metadata即(data, metadata)元组中的第二部分会被忽略。源码视角方法间的选取顺序与细节处理_repr_*_的选取逻辑在 marimo/_output/formatters/repr_formatters.py 的maybe_get_repr_formatter中实现其内部维护了一个按偏好排序的方法列表L84-L101顺序为_repr_html_→_repr_mimebundle_→_repr_svg_→_repr_json_→_repr_png_→_repr_jpeg_→_repr_markdown_→_repr_latex_→_repr_text_text/html被放在第一位优先尝试text/plain作为最后兜底。该方法列表还有一些值得了解的工程细节多个方法可共存只要对象实现了列表中的任意一个方法marimo 就会按上述顺序逐个尝试某个方法返回None则自动跳到下一个_repr_mimebundle_的参数兼容调用时会先尝试method(includeNone, excludeNone)失败或返回空再退化为无参调用返回的(data, metadata)元组会被解包metadata 被丢弃二进制数据自动转 data URLimage/*、audio/*、video/*、application/pdf等媒体类型若返回 bytes或 base64 字符串会被自动转换为data:URL 以便浏览器展示见 repr_formatters.py 的 MEDIA_MIME_PREFIXES 与转换逻辑anywidget 集成若 mimebundle 中出现application/vnd.jupyter.widget-viewjsonmarimo 会尝试将其转换为marimo-anywidgetHTML与mo.ui.anywidget()一致而传统 Jupyter widget 则原样传递并在前端显示错误横幅markdown/latex 转 HTML当 mimebundle 中没有text/html时text/markdown与text/latex内容会经mo.md渲染为 HTML。IPython 显示对象的兼容支持除了自定义类上的_repr_*_marimo 还对 IPython 的IPython.display对象做了专门的 formatter 适配见 marimo/_output/formatters/ipython_formatters.py。对应测试 tests/_output/formatters/test_ipython_formatters.py 验证了IPython.display.HTML渲染为text/html、IPython.display.Image的 GIF/PNG bytes 转换为data:image/*;base64,链接、URL 图片渲染为img标签等行为。Option 3实现_mime_()方法媒体查看器协议显示对象时marimo 的媒体查看器会检查对象是否实现了_mime_方法。该方法不接受参数返回一个包含两个字符串的元组MIME 类型 待显示的字符串数据。class MyJSONObject: def __init__(self, data: dict[str, object]) - None: self.data data def _mime_(self) - tuple[str, str]: return (application/json, json.dumps(self.data))该协议在 marimo/_output/mime.py 中以MIME协议类形式被正式定义。其 docstring 给出了媒体查看器支持的 MIME 类型清单包括application/jsonapplication/vnd.marimoerror、application/vnd.marimotracebackapplication/vnd.vega.v5json、application/vnd.vegalite.v5json、application/vnd.vega.v6json、application/vnd.vegalite.v6jsonimage/png、image/svgxml、image/tiff、image/avif、image/bmp、image/gif、image/jpegvideo/mp4、video/mpegtext/html、text/plain更完整的 MIME 类型字面量定义可参考 marimo/_messaging/mimetypes.py 的 KnownMimeType。从 formatting.py 的_mime_分支 可以看到一个补充细节若_mime_返回的 data 是bytes而非字符串marimo 会自动将其转换为 data URL 后再交给媒体查看器。完整示例JSON / HTML / 图片下面这段可运行在 marimo 编辑器中的完整示例源自原文档的 marimo-embed 代码块展示了用_mime_渲染 JSON、HTML 与图片三种场景import marimo as mo app mo.App() app.cell(hide_codeTrue) def __(): mo.md(**JSON**) app.cell def __(): import json class MyJSONObject(object): def __init__(self, data: dict[str, object]) - None: self.data data def _mime_(self) - tuple[str, str]: return (application/json, json.dumps(self.data)) MyJSONObject({hello: world}) app.cell(hide_codeTrue) def __(): mo.md(**HTML**) app.cell def __(): class Colorize(object): def __init__(self, text: str) - None: self.text text def _mime_(self) - tuple[str, str]: return ( text/html, span stylecolor:red self.text /span, ) Colorize(Hello!) app.cell(hide_codeTrue) def __(): mo.md(**Image**) app.cell def __(): class Image(object): def __init__(self, url: str) - None: self.url url def _mime_(self) - tuple[str, str]: return (image/png, self.url) Image(https://raw.githubusercontent.com/marimo-team/marimo/main/docs/_static/marimo-logotype-thick.svg) if __name__ __main__: app.run()如果你希望一次体验更多 MIME 类型SVG、CSV、markdown、Vega-Lite、自定义 mimebundle 组合等仓库中提供了一个现成的冒烟测试笔记本 marimo/_smoke_tests/mimes.py可直接在编辑器中打开观察各类_mime_与_repr_mimebundle_对象的实际渲染效果。三种方案如何选择方案语法复杂度是否需要 marimo 依赖适用场景_display_()最低不需要只想让对象在 marimo 中显示返回值能落到 marimo 已知类型如mo.Html、mo.ui、matplotlib 图等上对库开发者最友好_mime_()中不需要需要精确控制输出的 MIME 类型与数据例如输出 JSON、SVG、Vega-Lite 规范等 marimo 未预注册格式_repr_*_()中不需要希望对象同时在 IPython/Jupyter 生态与 marimo 中保持一致展示兼容已有 IPython 富显示代码需要注意的是如果返回值的类型 marimo 无法渲染例如你在构建全新的绘图库应优先考虑_mime_或_repr_*_方案直接产出标准 MIME 数据。纵深补充内置 formatter 注册机制与相关 API优先级链中排在_display_之后、_mime_之前的是 marimo 的内置 formatter。理解它有助于你更准确地预测对象会被如何渲染FormatterRegistry 与装饰器marimo 通过formatter/opinionated_formatter装饰器把「类型 → (mime, data) 转换函数」注册进两个注册表见 formatting.py 的 FormatterRegistry 与 formatter 装饰器。查找时既查精确类型也会沿类型的 MRO 继承链向上搜索并把结果缓存到具体类型上以加速后续查询。意见化 formatter 与mo.plainpandas、polars、Arrow 等数据框默认走意见化渲染即 marimo 定制的表格界面。当需要跳过这种定制展示、退回到普通文本表示时可以用mo.plain(value)包一层见 formatting.py 的 plain 函数这等价于把include_opinionated置为False。mo.as_html任何对象都可以通过mo.as_html(value)显式转换成可嵌入 Markdown/HTML 字符串的Html对象formatting.py#L280-L315这是把富对象嵌入mo.md文本的常用手段。协议探测的健壮性marimo 用 is_callable_method基于inspect.getattr_static探测_display_/_mime_/_repr_*_以避免__getattr__动态返回任意属性的对象如 pandas 的Expression误触发协议检测、造成无限递归。test_getattr_trap_does_not_recurse见 tests/_output/test_try_format.py正是针对这一回归场景的测试。错误兜底try_format会捕获 formatter 执行期间的任何异常并把 traceback 写入输出而不会中断单元格formatting.py#L226-L247test_error_handling测试覆盖了该行为。小结marimo 的富显示体系本质上是一个分层格式化管线_display_()提供返回任何可显示对象的最高层抽象内置 formatter 负责主流数据与绘图库的精致展示_mime_()提供精确的 MIME 级控制IPython_repr_*_协议则保证了与 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/marimo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表