跳转到内容

Jupyter

一个完整的 Jupyter 由 Notebook、Editor、Kernel 三部分组成。

  • Notebook 即笔记本是一个 JSON 文件,保存了文档、代码和运行结果。
  • Kernel 即内核负责执行代码,并保存着语言的运行时状态。
  • Editor 即编辑器负责修改 JSON 文件并与内核通信。

因此,完整的 Jupyter 就是一个开发环境。

Notebook 是一个持久化 JSON 文档,编辑器对其进行解析、渲染和修改。

Kernel 是一个更高级的、有状态的、可远程通信的 REPL。内核会持续运行,是独立进程,保存语言运行时状态,并通过 Jupyter 消息协议提供代码执行和交互能力。

Editor 是一个 Notebook 文档编辑器,同时也是 Kernel 的客户端。编辑器根据 Jupyter 消息协议,把 *.ipynb 里的代码块作为请求发给内核,再把内核返回的消息转换为代码块的输出,最后写入时序列化为 JSON。

因此,Kernel 是语言的临时状态,Notebook 是持久化的文档,而 Editor 在二者之间架起桥梁。

flowchart LR
    Editor["Editor"]
    Editor -->|读取和写入| Notebook["Notebook"]
    Editor -->|发起请求并得到结果| Kernel["Kernel"]

Jupyter 使用特殊的 .ipynb 文件格式,可以将文档、代码、运行结果等放在一起展示。具体的渲染效果和编辑器有关。

  • 文档使用 Markdown 格式,运行结果中不仅包含文本输出,还可能有图片、可交互组件等内容。
  • 代码支持不同的语言,编辑器可以直接渲染,但执行需要分别安装对应的内核。

Jupyter 的这种笔记本格式可以把代码、文本、图片、公式、图表作为一个复合文档统一展示。别人打开笔记本时可以看到你记录的完整分析过程、所有源代码和全部运行结果,也可以简单地重新运行部分代码看看是否能够复现。

这种笔记本格式也可以使用工具(比如 nbconvert/jupytext/pandoc)导出为别的格式,包括但不限于 HTML / PDF。

Jupyter 由于编辑器和内核分离的架构设计,天然适合远程开发。这使得 Jupyter 在人工智能和科学计算领域非常流行。这些领域非常依赖机器性能,有了 Jupyter 后只需用轻薄本连上一个强大的远程服务器,就可以愉快地开发了。

Jupyter 代表了一种新的编程方式——探索式编程。这可以看作一种更高级的 REPL。代码写在一个个代码块里,可以单独运行一个代码块,也可以一次运行多个选定的代码块。而这些代码运行后,内核保存着运行时的状态,再运行新的代码块不需要重新启动进程,可以在之前的状态上继续。

比如对于机器学习任务,需要先导入大型库和巨量数据集,然后才能定义模型并设定一些参数进行训练,最后还要根据训练的效果返回去调整参数或模型。Jupyter 可以让调整的时候,不用重新导入库和数据集。这极大地提升了探索和调试的效率。

一些 Jupyter 内核还提供了魔法命令,包含很多实用功能,比如直接运行外部命令。这使得 Jupyter 不仅仅是一个编辑器,而成为了一个集成开发环境。

Jupyter 为了远程开发和多语言支持而设计了复杂的架构。因此,想要本地使用 Jupyter,要同时有编辑器和内核。当然,如果只进行远程开发,那么本地有编辑器就行了,内核可以运行在别的机器上。

如果使用 VSCode,那么需要下载 Jupyter 扩展。

如果使用 JupyterLab,那么可以通过 pip install jupyterlab 安装。

内核根据语言选择。Python 的内核一般用 ipykernel,可以通过 pip install ipykernel 安装。

可以在 https://github.com/jupyter/jupyter/wiki/Jupyter-kernels 上找到目前能用的所有内核。

使用 VSCode 作为编辑器可以参考 官方文档,里面有很详细的使用方法说明。

使用 JupyterLab 需要启动或连接一个 JupyterLab 服务。本地使用时可以在项目根目录运行命令启动服务器。

Terminal window
jupyter lab

服务器启后会自动在浏览器中打开给定的 URL。

后续的使用方法可以参考 官方文档

导出可以使用 nbconvert,通过 pip install nbconvert 安装。VSCode 的导出实际上就使用了 nbconvert

nbconvert 支持导出为多种格式,不过最常用的还是 HTML 和 LaTeX。而 PDF 可由二者进一步处理得到。

Terminal window
# 将 example.ipynb 导出为 export.html
jupyter nbconvert example.ipynb --to html --output export

一些常用的选项

  • --template 指定模板。HTML 导出可使用 lab / classic 等内置模板,也可以自定义模板或下载社区里的模板。
  • --no-prompt 不保留提示符
  • --clear-output 清除代码块输出,同时也会修改原笔记本。如果只需要在导出的文档中隐藏代码块输出,可以使用 --TemplateExporter.exclude_output=True

之后可以用浏览器的打印功能,将 *.html 文件转为 PDF。如果偏爱脚本也可以用 无头浏览器 来打印

导出为 LaTeX 还需要安装 Pandoc

Terminal window
# 将 example.ipynb 导出为 export.tex
jupyter nbconvert example.ipynb --to latex --output export

如果原 ipynb 文件中有图片等非文本输出,则上述命令会创建一个文件夹 export_files 来保存这些文件。

LaTeX 导出默认使用 latex 模板,可以自定义模板或下载社区里的模板。

之后就是编译 tex 文件得到 PDF,这要求本机已安装 TeX 环境

Terminal window
xelatex export.tex --quiet

nbconvert 直接将 ipynb 转为 PDF,其实就是把转为 LaTeX 和编译 LaTeX 的步骤结合起来了。

另一种常见的导出目标是 py 文件,这方面我认为 jupytextnbconvert 做得更好。jupytext 同样可通过 pip install jupytext 安装

Terminal window
# 将 notebook.ipynb 转为 notebook.py
jupytext --to py notebook.ipynb

这种转换会丢失代码块输出和部分元数据,但 jupytext 允许把 py 反向转换回 ipynb

导出 md 也是可行的,同样更推荐使用 jupytext

Terminal window
# 将 notebook.ipynb 转为 notebook.md
jupytext --to md notebook.ipynb

这种转换同样会丢失代码块输出和部分元数据,且 jupytext 同样支持反向转换回 ipynb

除了可以将 ipynb 导出为别的格式外,也可以把别的格式转换为 ipynb 文件。

前面已经提到 jupytext 可以将 md / py 文件转为 ipynb 文件。这一转换虽然不是无损的,但 Markdown 文档和 Python 代码都会被完整保留。

Terminal window
# 将 notebook.py 转为 notebook.ipynb
jupytext --to notebook notebook.py
# 将 notebook.md 转为 notebook.ipynb
jupytext --to notebook notebook.md

如果想只将 md/py 提交版本控制系统从而方便查看变更,但同时又想保留 ipynb 即时探索的流畅性,那么可以用 Jupytext 的配对功能 同步文本文件与 ipynb

至于选择 md 更好还是 py 更好则因人而异。我的一个 ipynb 文件原始 JSON 有 2000 多行,转为 mdpy 后都只剩下了 500 行左右

  • 转为 py 后可以直接使用 python notebook.py 运行代码,但所有的 markdown 内容都写在注释里,编辑器不会高亮 markdown,且无法用 markdown 渲染器进行阅读。
  • 转为 md 后所有 python 脚本都在代码块里,编辑器能够同时高亮 markdown 和 python,且可以使用 markdown 阅读器,但没法通过 python notebook.md 直接运行代码。不过能使用 jupytext --to notebook --execute notebook.md 来执行并转换这个 md 文件。

Jupyter 的命令行工具除了可以启动服务器、进行导出外,还有别的功能。

比如 jupyter kernelspec list 可以列出当前能用的所有内核。

更多的用法可以通过 jupyter --help 来查看。