Panel 是 HoloViz 生态中的开源 Python 库,面向数据类 Web 应用与仪表盘的快速构建。它几乎让“数据应用”的全部工作在 Python 侧完成:组件(按钮、滑块、输入框)、布局(网格、侧边栏、多标签页)、图表(Bokeh、Matplotlib、Plotly、Altair、ECharts 等十余种渲染后端)以及表格(Tabulator)都以 Python 对象的形式组合与响应,不需要编写 HTML、CSS 与 JavaScript。同类型的工具是 Streamlit、Dash 与 Gradio,但 Panel 的独特之处在于它自带完整的服务端事件循环与前端模型层,既能像 Jupyter 笔记一样即时预览,也能通过一条命令部署为独立 Web 服务,甚至能转换成不依赖 Python 服务端的 WebAssembly 静态文件。 下文按「能力概览 → 安装配置 → 快速上手 → 核心能力 → 生产部署」的顺序展开,并在最后给出与主流替代品的对比、常见误区与面试题,让你在 30 分钟内把第一个可交互仪表板跑起来。
对 AI 从业者来说,掌握 Panel 意味着你能把模型推理、数据分析和 RAG 检索结果快速包装成可交付的产品原型,是连接 notebook 研究与生产演示之间最短的桥梁之一。
目录
速览卡是工具类内容的固定首屏模块:30 秒判断「这工具是什么、能不能商用、适不适合我」。
为什么需要 Panel:数据应用前后端分离的痛点 → 单一 Python 栈
传统的数据应用交付路径是:先在 Jupyter 里做原型,再把图表代码交给前端工程师改写成 HTML/JS,最后通过 Flask 或 Django 提供数据接口。这条路径的问题在于——Jupyter 的交互输出依赖内核存活,无法直接给非技术用户使用;前后端联调时事件绑定、状态同步和 WebSocket 通信的代码量往往超过业务逻辑本身;而大部分分析师和机器学习工程师并不熟悉前端工具链。结果是,大量本可以快速见效的数据产品停留在 notebook 阶段,迟迟无法上线。
Panel 的解法是把整个 Web 应用的“前端”抽象成一组 Python 对象。你在 Python 中声明一个小部件,把它放进一个布局,再把这个布局标记为可服务,Panel 自动生成对应的 Bokeh 模型并推送到浏览器。更关键的是它的响应式绑定机制:pn.bind 和 @pn.depends 能把小部件当前值注入到一个普通函数里,函数返回值的变化自动触发界面更新,不需要手写回调或管理视图状态。这种“声明式 + 自动依赖追踪”的模型,让一个数据分析师也能独立完成数据应用的全栈开发。
与同类工具相比,Panel 的气质介于 Streamlit 和 Dash 之间:Streamlit 是“脚本重跑”模型,适合快速原型但难以精细控制布局与状态;Dash 是“回调注册”模型,功能强大但学习成本集中在 React 式组件与回调规范上;Panel 则保留了 Python 对象的组合性,同时拥有最宽的图表库兼容面和对独立 WASM 部署的原生支持,适合需要长期演进、多图表混用、甚至离线交付的团队。
安装与环境配置:3 步就绪
第一步,创建并激活虚拟环境。推荐使用 venv 或 Conda,避免与系统 Python 包冲突。
第二步,安装 Panel 本体。pip install panel 会同时安装 Bokeh、Param、Tornado 等核心依赖。如需常用数据生态,可一并安装 pandas、numpy、plotly、matplotlib。
第三步,验证安装。执行 panel --version 查看 CLI 版本,并用 python -c "import panel as pn; print(pn.__version__)" 确认 Python 包可用。
如使用 JupyterLab 或 Notebook,无需手动安装扩展——现代版本中 pn.extension() 会自动完成前端资源的加载,这也是笔记场景下最容易忽略的一步。
# 1. 创建并激活虚拟环境python -m venv .venvsource .venv/bin/activate # Windows: .venv\Scripts\activate # 2. 安装 Panel 及常用数据依赖pip install panel pandas numpy matplotlib # 3. 验证安装panel --versionpython -c "import panel as pn; print(pn.__version__)"
快速上手:10 分钟跑通第一个仪表板
最小可用流程的思路是:写一个 Python 脚本,在其中完成“定义小部件 → 用 pn.bind 把函数与小部件值绑定 → 用模板拼装布局 → 调用 .servable() 标记可服务”,然后用 panel serve 启动。整个过程不需要创建任何 HTML 文件。
具体操作分三步:
1. 新建 app.py,编写如下代码。核心是 @pn.depends(threshold) 装饰器:它声明了函数 mean_sales 依赖小部件 threshold,滑块值一变,函数自动重新执行并刷新输出。
2. 在终端运行 panel serve app.py,默认监听 localhost:5006,浏览器打开即可看到带左侧边栏的仪表板。
3. 如需在 Jupyter 中预览,在同一 notebook 的代码末尾调用 app.show(),或在单元格中直接显示 app 对象。
运行后你会看到:左侧是滑块,右侧是统计文本和数据表格;拖动滑块时,统计文本立即更新,表格保持静态(这是演示“仅刷新依赖部分”的刻意设计)。进阶技巧:把 pn.pane.DataFrame(data, height=300) 换成 pn.widgets.Tabulator(data),表格本身也会变成可排序、可筛选的交互组件。
import panel as pnimport pandas as pdimport numpy as np pn.extension() # Jupyter 中必须先调用;纯脚本模式可省略 # 1. 准备数据data = pd.DataFrame({ "month": pd.date_range("2024-01", periods=12, freq="ME"), "sales": np.random.default_rng(7).normal(1000, 50, 12),}) # 2. 定义小部件threshold = pn.widgets.IntSlider( name="最低销售额", start=800, end=1200, step=10, value=900) # 3. 绑定计算函数(依赖注入小部件值)@pn.depends(threshold)def mean_sales(t): sub = data[data["sales"] >= t] return f"符合条件 {len(sub)} 个月,平均销售额 {sub['sales'].mean():.0f}" # 4. 组合布局并标记可展示app = pn.template.FastListTemplate( title="销售月度看板", sidebar=[threshold], main=[mean_sales, pn.pane.DataFrame(data, height=300)],)app.servable()
核心能力详解:4 大支柱
支柱一 · 声明式小部件与响应式绑定。 Panel 的交互模型建立在“依赖图”之上。pn.bind(func, widget) 创建一个包装函数,它读取 widget 的当前值作为 func 的位置参数;@pn.depends(widget) 则声明式地订阅一个或多个小部件,任意一个变化都会触发函数重算并更新输出。pn.rx(reactive expression)则提供运算符级别的响应式表达式——例如 pn.rx(threshold) * 2 会随阈值变化实时重算。三者共同构成从简单回调到复杂数据流的完整控制粒度。
支柱二 · 多图表库统一渲染。 Panel 的 pn.pane 命名空间内置了 30 余种 Pane(渲染容器),Bokeh、Matplotlib、Plotly、Altair、Vega、ECharts、Leaflet 地图、视频/音频/PDF 等对象传入后自动转换为可交互 Web 组件。这意味着同一个布局里可以混插不同图表库的产物,无需为每个库写独立的 Web 适配层。这也是 Panel 相比 Streamlit 生态集成面更宽的核心优势。
支柱三 · 模板与设计系统。 pn.template 提供 FastListTemplate、FastGridTemplate、MaterialTemplate、AdminTemplate 等预置布局,统一处理页头、侧边栏、主内容区和主题色。通过 pn.config.design 可以切换 Material/Boostrap 等设计系统,调整小部件的视觉风格,而无需手写 CSS。对于需要严格品牌定制的场景,Template 支持覆盖 Jinja2 模板文件,但大多数内部工具用内置模板已足够。
支柱四 · 服务端渲染与 WASM 静态导出。 运行 panel serve app.py 时应用跑在 Tornado 服务上,这是默认且功能最完整的运行模式。而 panel convert app.py --to pyodide-worker --out dist 会把应用连同 Python 运行时(Pyodide)打包成纯静态文件,交给任意静态服务器即可在浏览器中运行,客户端与数据库交互需改为调用 HTTP API。部署形态上 Panel 同时覆盖“有服务器”和“无服务器”两种场景,这在同类工具中极少见。
生产部署与监控:从上线到运维
方式一 · 服务端进程部署。 panel serve 本身支持 --port、--address、--num-procs(多进程)与 --allow-websocket-origin(限制 WebSocket 接入域名)。生产实践中通常用 systemd 或 Docker 托管该进程,前面挂 Nginx 做 TLS 终止与反向代理,Nginx 需将 /wss 或 /panel 路径的 WebSocket 升级请求正确转发。多进程模式下各 worker 进程独立运行,内存中的 Python 状态互不可见,因此需要跨进程共享的数据(如缓存)应交给 Redis 等外部存储。
方式二 · WASM 静态部署。 运行 panel convert app.py --to pyodide-worker --out dist --requirements requirements.txt 后,dist/ 目录即是可直接托管的静态站点。Pydodide 会下载约 10-30MB 的 Python 运行时到浏览器,应用逻辑在浏览器本地执行,天然支持高并发、低成本、零服务器。局限在于:纯 Python 依赖可直接打包,但含 C 扩展且未编译到 Pyodide 的库(如部分数据库驱动)不可用;文件系统与本地硬件访问受限,需通过浏览器的 IndexedDB 与外部 API 解决。
可观测性。 Panel 不内置指标面板。日志方面,panel serve --log-level info 输出访问日志,应用内使用标准 logging 即可将业务日志打到 stdout,由日志采集器(Loki、CloudWatch 等)统一收集。进程健康检查可用 TCP 端口探测;更细粒度的业务指标(如每次请求耗时、依赖计算次数)建议在 pn.state.onload 或绑定函数内部用 Prometheus 客户端手动埋点。Nginx access log 是分析访问量最直接的来源。WASM 模式下无服务端日志,监控退化为前端错误探针(如 Sentry 的 Python 版本),需提前在架构上做好取舍。
<p class="para-label">避坑清单:</p>
<ul class="dash-list"><li>忘记调用 pn.extension():在 Jupyter 场景下组件可能出现空白或样式错乱,务必在导入后先执行一次;纯 panel serve 脚本则无此要求。</li><li>把 pn.serve() 当生产部署:notebook 内的 pn.serve() 仅为交互预览,缺乏 --allow-websocket-origin 等生产参数,上线请统一走 panel serve 命令行。</li><li>WASM 导出不声明依赖:缺 --requirements 时浏览器端会因缺少包而报错,且 C 扩展库可能根本无法在 Pyodide 中运行,先验证依赖是否纯 Python。</li><li>用 on_click 手动更新全局状态:应优先用 pn.bind/@pn.depends 让数据流自动响应,手动写 widget.value = ... 容易造成界面与数据不一致。</li><li>忽略 Tornado 与 Django/Flask 的事件循环冲突:将 Panel 嵌入现有服务需要共享事件循环,建议直接用独立进程部署,避免两套生态互相干扰。</li></ul>
| 维度 | Panel | Streamlit | Dash(Plotly) | Gradio |
|---|---|---|---|---|
| 定位 | 数据应用框架(可视化生态最宽) | 数据科学快速原型工具 | 企业级数据仪表盘框架 | ML 模型演示与分享工具 |
| 编排范式 | 声明式对象组合 + 依赖图绑定 | 自上而下脚本重跑 | 回调注册(Callback) | 接口函数包装(Inputs/Outputs) |
| 类型约束 | 有类型系统(Param/pydantic) | 动态类型为主 | 动态类型 + 自定义组件 | 以接口 schema 为准 |
| 学习曲线 | 中;需理解 Pane/依赖绑定概念 | 低;10 分钟可写首个应用 | 较高;需消化回调规范 | 低;围绕函数签名即可 |
| 生态集成 | 支持 Bokeh/Plotly/Matplotlib/Altair/ECharts 等 30+ 渲染后端 | 内建组件丰富,第三方少 | Plotly 图表为第一公民,其他库需封装 | 以图像/音频/视频为主,图表较弱 |
| 生产部署 | `panel serve` 多进程 + WASM 静态导出双路线 | 单进程为主,需自行扩展 | Flask 服务,适合嵌入现有 WSGI 架构 | 自带分享隧道,生产需自托管 |
| License | BSD-3-Clause | Apache-2.0 | MIT | Apache-2.0 |
| 适合谁 | 需要复杂布局、多图表库混用与离线交付的团队 | 分析师快速验证想法与建内部工具 | 企业内已选型 Plotly 的正式仪表盘项目 | 快速分享模型 Demo 给非技术人员 |
选型建议:如果你是分析师或 ML 工程师,只想最快把一个模型接口变成可交互 Demo,选 Streamlit 或 Gradio 更省力。如果你的应用需要长期演进、混用多个图表库、控制布局到像素级,或者可能要脱离服务器交付(内部工具、离线展示),选 Panel。Dash 更适合已经在企业级 Web 架构中深度绑定 Plotly 的技术团队,它对 Flask 生态的兼容性是迁移成本最低的路线。
版本迭代
Panel 自 2019 年加入 HoloViz 生态后,经历了从“Jupyter 组件库”到“独立 Web 框架”的转变。1.0 是 API 稳定化的分水岭,1.3 起面向 AI 场景补齐聊天组件,1.5 之后把 WASM 静态导出作为生产级部署选项,版本主线始终围绕“Python 对象即前端”这一核心承诺。
| 版本 | 时间 | 变化 | 提升 |
|---|---|---|---|
| 1.0 | 2023-11 | 正式稳定版,全面重写组件层 | 同步、面向对象的组件 API;移除旧参数系统;与 Bokeh 3 对齐 |
| 1.3 | 2024-03 | Chat 聊天接口 | 新增 `pn.chat.ChatInterface`,支持与 LLM 流式对话输出 |
| 1.4 | 2024-05 | 数据表格与配置命令 | 推出可编辑的 `Tabulator` 表格;新增 `panel configure` 管理依赖 |
| 1.5 | 2024-10 | WASM 部署增强 | `panel convert --to pyodide-worker` 支持浏览器端独立运行;服务端渲染提速 |
| 1.6 | 2025-01 | 互操作与性能优化 | 改进 JupyterLite 集成与 TypeScript 扩展开发体验;优化启动速度与内存占用 |
Panel 的版本节奏稳定,每季度一次大版本,核心趋势是「浏览器端能力增强」与「AI 场景适配」。如果团队要构建 LLM 应用界面并追求零服务端部署,优先选 1.5 以上版本;如果只做普通数据仪表板,1.4 已足够稳定;追求最新互操作能力则直接用 1.6.x 系列。更新的小版本(1.6.x)以缺陷修复为主,升级成本低,建议保持跟随。
AI 应用场景
数据团队内部指标大屏
阶段:RAG 管道构建 / 数据可视化
解决的问题:数据团队每周人工用 Excel 汇总各渠道指标,生成 PPT 耗时 1-2 天,且无法交互筛选。使用 Panel 后,将 SQL 查询结果注入 pn.widgets.Tabulator 与 Plotly 图表,通过 FastGridTemplate 拼装指标卡片与趋势图,筛选器绑定 @pn.depends 函数实现联动刷新,非技术人员在浏览器中即可自助查看。
具体案例:某增长团队用 150 行 Panel 脚本替代原先的周报流程,将“数据查询 + 可视化 + 分享”压缩到 1 小时内完成,报表从每周人工更新一次变为实时可访问。
LLM 应用调试与演示台
阶段:Agent 编排 / LLM 交互界面
解决的问题:调试 RAG 或 Agent 时需要反复修改 prompt 参数并观察流式输出,notebook 界面不便于非技术同事试用。Panel 的 pn.chat.ChatInterface 提供现成的类 ChatGPT 界面,回答可流式渲染;配合 pn.widgets.TextAreaInput 调节 temperature、top_k 等参数,实现“参数-输出”联动,大幅缩短调试反馈回路。
具体案例:某 AI 应用团队用 80 行 Panel 代码构建内部评测台,支持同时对比 3 个模型的流式回答并记录评分,模型实验周期从每次 15 分钟手工记录缩短至 5 分钟内完成一轮对比。
机器学习模型交付与 AB 展示
阶段:模型部署 / 线上效果演示
解决的问题:模型训练完成后,业务方难以直观理解输出效果。Panel 把模型推理函数包装进 pn.bind,输入端用评分卡、下拉框等小部件收集样本特征,输出端同时渲染预测结果、概率分布图和特征重要性,甚至提供 WASM 静态版供离线演示。业务方无需任何配置即可在浏览器中“试”模型。
具体案例:某风控团队将信贷评分模型封装为 Panel 演示页,支持输入 12 个特征字段并实时返回拒绝/通过建议与置信度,模型汇报评审周期从 2 周缩短至 3 天。
常见误区
误区Panel 是 Jupyter 的插件,没有 notebook 环境就跑不起来,所以只能当原型工具用。
正解Panel 完全独立于 Jupyter。pip install panel 后可直接 panel serve app.py,应用运行在 Tornado Web 服务上,与 notebook 内核无关。Jupyter 集成只是它的可选能力,用来在 notebook 里即时预览。生产环境甚至不需要安装 Jupyter。
为何常见:官方文档大量展示 notebook 内嵌效果,且大部分入门教程都从 Jupyter 讲起,很容易让人以为它是 notebook 的附属品。
误区在代码里调用 `pn.serve(app)` 把应用跑起来,就等于完成上线了。
正解pn.serve() 的主要用途是在 notebook 或脚本中进行交互式启动,缺少生产所需的进程管理、域名限制、多 worker 等能力。「部署」的正确方式是 panel serve app.py,再用 systemd/Docker/Nginx 包裹。命令行模式还提供 --allow-websocket-origin 等安全相关参数,这是 pn.serve() 不具备的。
为何常见:二者共享同一个“serve”名字,且 notebook 内调用 pn.serve() 的启动效果与命令行在视觉上非常相似,区分只在参数与运行上下文。
误区`panel convert --to pyodide-worker` 把应用打包成静态文件后,Python 的库和功能应该原封不动地搬到浏览器里。
正解WASM 模式受 Pyodide 运行时约束:纯 Python 库可直接导入,但依赖 C 扩展且未经 Pyodide 编译的库(如部分数据库驱动、加密库)无法运行;文件系统访问也受限。打包阶段必须用 --requirements 显式声明依赖,并在 Pyodide 包索引中确认其可用性。适合纯 pandas/numpy/Panel 栈的只读型应用,不适合需要频繁读写本地数据库的重型服务。
为何常见:因为 Pyodide 已经能跑 numpy/pandas 等重量级库,使用者自然会期待“所有库都能跑”,忽略了编译型依赖的边界。
误区既然都是实现“小部件变化触发函数重算”,那两种写法随便选就行。
正解二者语义不同。pn.bind(func, widget) 是把 widget 当前值作为参数注入函数并生成一个新的可调用对象,适合在函数调用时取值;@pn.depends(widget) 是声明性的依赖追踪——它建立函数级依赖图,任意依赖变化都会自动重算并将结果推到输出组件的 model 中。混用场景下(如在类方法中同时使用两者)评估顺序不同,可能导致重复计算或绑定失效。最佳实践:普通函数用 pn.bind 取当前位置值,需要持续订阅多个依赖时用 @pn.depends。
为何常见:官方示例中两者都可以在简单场景下完成“滑块 → 文本更新”,使用者不深入阅读返回值类型与依赖图语义,便容易视为等价。
误区Panel 擅长展示图表,但像“用户填表提交”这类经典 Web 表单场景它干不了。
正解pn.widgets 提供文本输入、下拉、多选、滑块、日期选择、文件上传、数据帧编辑器等完整表单控件,配合 pn.state 的会话状态与 pn.widgets.Button 的点击事件,可以实现带校验和提交逻辑的复杂表单。非标准的业务组件还可以通过自定义 TypeScript component 扩展,与 Bokeh model 对接。
为何常见:入门教程大多以“图表 + 滑块”为演示对象,导致用户低估了它的表单能力;实际上 Panel 的控件层与布局系统已经覆盖轻量级 Web 表单的全部要素。
面试题
Q1. 下列哪个命令用于启动 Panel 应用服务器?
- A.
python run.py - B.
panel serve app.py← 正确答案 - C.
streamlit run app.py - D.
bokeh serve app.py
答案:B。panel serve app.py 是 Panel 官方 CLI 启动命令。python run.py 仅在脚本内部调用 .servable() 后有效;streamlit run 属于 Streamlit;bokeh serve 可加载 Bokeh 应用但不解析 Panel 的组件与绑定。
Q2. 在 Jupyter 中使用 Panel 组件前,通常必须先执行哪一步?
- A.
pn.extension()← 正确答案 - B.
panel.start() - C.
pn.serve(app) - D.
import bokeh
答案:A。pn.extension() 负责加载前端资源并注册自定义组件,是 notebook 场景的固定第一步。panel.start() 与 pn.serve(app) 用于启动服务,不属于 notebook 内常规初始化;import bokeh 只是底层依赖,不解决 Panel 资源加载问题。
Q3. Panel 的数据表格组件(支持排序、筛选、编辑)是哪个?
- A.
pn.widgets.DataFrame - B.
pn.widgets.Tabulator← 正确答案 - C.
pn.pane.Markdown - D.
pn.widgets.LiteralInput
答案:B。pn.widgets.Tabulator 基于 Tabulator 库,提供列排序、筛选、分页与单元格编辑。旧版 pn.widgets.DataFrame 已不是推荐表格组件。pn.pane.Markdown 是文本渲染,LiteralInput 是字面值输入控件。
Q4. pn.bind(func, widget) 返回的对象是什么?
- A.小部件的当前值
- B.一个将 widget 当前值注入 func 的可调用包装函数← 正确答案
- C.一个布尔依赖标志
- D.渲染完成的 Pane 对象
答案:B。pn.bind 返回闭包,调用时读取 widget.value 并作为 func 的位置参数传入。它不等于 widget 的值,也不是布尔标志;返回的对象需放置在布局中,由 Panel 在依赖变化时自动重算并更新显示的 Pane。
Q5. Panel 的核心渲染模型建立在哪个底层库之上?
- A.Plotly.js
- B.Bokeh← 正确答案
- C.D3.js
- D.React
答案:B。Panel 的模型层基于 Bokeh 的 Document/Model 架构,组件状态通过 Bokeh 协议同步到浏览器。Plotly.js 与 D3 是可选渲染后端之一,React 则是 Dash 的地基。Bokeh 是 Panel 组件系统的前提。
Q6. 以下哪个组件最适合构建与 LLM 对话的聊天界面?
- A.
pn.chat.ChatInterface← 正确答案 - B.
pn.template.AdminTemplate - C.
pn.pane.Video - D.
pn.widgets.FloatSlider
答案:A。pn.chat.ChatInterface 是 Panel 1.3 起提供的聊天组件,内置消息气泡、输入框与流式输出支持。AdminTemplate 是管理后台布局,Video 是视频播放,FloatSlider 是浮点滑块,均与对话交互无关。
Q7. 将 Panel 应用导出为浏览器端独立运行的静态文件,使用哪个命令?
- A.
panel export --standalone app.py - B.
panel convert app.py --to pyodide-worker← 正确答案 - C.
panel build --wasm app.py - D.
panel package app.py --static
答案:B。panel convert --to pyodide-worker 是官方 WASM 导出命令,产物为纯静态目录。其余三个命令在 Panel CLI 中不存在,属干扰项。转换后的应用由 Pyodide 在浏览器中解释执行。
Q8. 使用 Nginx 反向代理 panel serve 时,下列哪个参数最容易被遗漏且会导致长连接断开?
- A.
--num-procs 4 - B.
--allow-websocket-origin api.example.com← 正确答案 - C.
--log-level info - D.
--port 8080
答案:B。Panel 使用 WebSocket 推送更新,浏览器发起连接时带 Origin 头,服务端默认拒绝未授权的来源。不设置 --allow-websocket-origin 会出现页面打开正常、交互不更新的典型故障。--num-procs 影响性能而非连接合法性,--log-level 与 --port 均不影响 WebSocket 握手。
Q9. 下列哪些机制可以实现 Panel 组件的响应式更新?(多选)
- A.
pn.rx← 正确答案 - B.
pn.bind← 正确答案 - C.
@pn.depends← 正确答案 - D.
pn.pane.Str
答案:ABC。pn.rx 提供运算符级响应式表达式,pn.bind 与 @pn.depends 分别以参数注入和依赖声明实现函数级响应更新,三者都是官方推荐的响应式机制。pn.pane.Str 仅负责把字符串渲染为对象,本身不具备订阅依赖的能力。
Q10. 关于 Panel 在 WebAssembly(Pyodide)模式下运行,下列哪些说法正确?(多选)
- A.依赖库需在构建时用
--requirements明确声明← 正确答案 - B.可以直接访问本地文件系统与数据库
- C.含未编译 C 扩展的库可能无法运行← 正确答案
- D.应用最终不依赖 Python 服务端← 正确答案
答案:ACD。WASM 模式下浏览器需提前知晓全部依赖,因此 --requirements 必填;Pyodide 仅包含已编译为 wasm 的包,纯 Python 之外的大量 C 扩展不可用,故 C 也正确;页面加载后应用逻辑全部在浏览器内执行,D 为 True。B 错误——浏览器沙箱禁止直接读写本地文件系统与原生数据库连接,需改用 HTTP API 或 IndexedDB。