什么是 Jupyter Notebook
Jupyter Notebook 是一种基于 Web 的交互式计算环境,允许你在同一个文档中混合编写代码、执行代码、查看输出、撰写文本说明和插入图表。
名称 "Jupyter" 来源于三种核心编程语言:Julia、Python、R,但现在已支持 40+ 种语言的 Kernel。
INFO
Jupyter Notebook 由 IPython 项目演化而来。2014 年,Fernando Pérez 等人将 IPython Notebook 独立出来,并重命名为 Jupyter Project。
核心理念:文学化编程
Jupyter 实践了 Donald Knuth 提出的"文学化编程"(Literate Programming)思想——代码应该像文章一样可读,附带完整的说明与推导过程。
传统的 Python 脚本 .py,运行后只能在终端看到输出,代码和结果是分离的。而 Jupyter Notebook 让代码、输出、文字说明、图表全部内联在同一个文档中,形成完整的叙事链条。
传统 Python 脚本 (.py)
- 纯文本代码文件
- 需运行整个脚本
- 输出打印到终端
- 图表弹出窗口
- 难以夹杂文字说明
Jupyter Notebook (.ipynb)
- 代码 + 输出 + 文档一体
- 可逐个单元格执行
- 输出内联显示
- 图表直接嵌入文档
- 支持 Markdown 和 LaTeX
典型使用场景
- 数据探索与分析
- 逐步加载数据、清洗、统计描述、可视化,边做边记录每步的发现。
- 机器学习实验
- 训练模型、调参、对比不同方案,每次实验的结果直接保存在 Notebook 中。
- 学术报告与论文附件
- 将分析过程和代码一同发布,让他人可以复现结果。
- 教学演示
- 老师在课堂上边讲边运行代码,学生直接打开相同的 Notebook 动手操作。
- 数据新闻与可视化报道
- 《纽约时报》、FiveThirtyEight 等媒体发布带完整分析过程的 Notebook。
.ipynb 文件格式
Notebook 文件以 .ipynb(IPython Notebook)为扩展名,本质是一个 JSON 文档:
// demo.ipynb 的简化结构 { "nbformat": 4, "metadata": { "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python", "version": "3.12.0" } }, "cells": [ { "cell_type": "markdown", "source": "# 我的分析报告\n\n这是一个 **Markdown** 单元格。" }, { "cell_type": "code", "execution_count": 1, "source": "print('Hello, Jupyter!')", "outputs": [{ "output_type": "stream", "text": "Hello, Jupyter!\n" }] } ] }
TIP
由于
.ipynb 是纯文本 JSON,可以用 git 进行版本控制。但因为输出内容(尤其是 Base64 图片)会让 diff 很难阅读,建议使用 nbstripout 工具在提交前自动清除输出。
Jupyter 生态系统
Jupyter 不只是一个工具,而是一个完整的生态:
| 组件 | 用途 |
|---|---|
| Jupyter Notebook | 经典界面,适合单文件分析 |
| JupyterLab | 下一代 IDE 界面,多面板、文件管理 |
| JupyterHub | 多用户服务器,适合团队和教学 |
| nbconvert | 将 Notebook 导出为 HTML/PDF/Python |
| ipywidgets | 交互式 UI 控件(滑块、按钮等) |
| nbviewer | 在线渲染 Notebook(无需安装) |
| Google Colab | Google 托管的云端 Jupyter 环境 |
Kernel 是什么
Kernel(内核)是在后台运行的编程语言进程,负责执行单元格中的代码并返回结果。
Notebook 界面(浏览器)通过 WebSocket 与 Kernel 通信。这意味着:
- 你关闭浏览器标签页,Kernel 仍在运行
- 所有单元格共享同一个 Kernel 进程,变量在整个会话中保持
- 可以为不同的 Notebook 使用不同的 Kernel(Python 2/3、R、Julia)
# 在一个单元格中定义变量 x = 42 # 在另一个单元格中可以直接使用 print(x) # 输出: 42
WARNING
变量的值取决于执行顺序,而不是单元格在文档中的顺序。如果你反复修改并重新运行某个单元格,可能会产生意想不到的变量状态。养成定期使用 "Restart & Run All" 的习惯,确保结果可复现。
Notebook 与脚本的深层区别
执行模型的差异
Python 脚本从第一行到最后一行顺序执行,执行一次产生一次结果。Notebook 的执行单位是单元格(cell),可以任意顺序、反复执行单个单元格。这使得探索性分析变得高效——发现数据问题时,只需修改并重新运行相关的 cell,而不必重头运行整个脚本。
状态持久化
所有已执行的单元格共享同一个 Kernel 进程的内存状态。这是双刃剑:好处是可以逐步构建复杂对象(如大型 DataFrame);坏处是乱序执行会导致变量状态混乱,形成难以复现的"隐式状态"问题。生产环境的 Notebook 必须支持从头到尾顺序执行得到相同结果。
.ipynb 格式的版本控制挑战
.ipynb 文件包含输出(包括 Base64 编码的图片),git diff 会显示大量与代码无关的二进制差异。解决方案:使用 nbstripout 在 git commit 前自动清除输出;或用 nbdime 工具做 Notebook 专用的 diff 和 merge。团队协作时需要在项目中配置这些工具。
云端 Jupyter:Google Colab
Google Colab 是基于 Jupyter 的免费云端环境,提供 GPU/TPU 支持,无需本地安装,适合快速实验和教学。与本地 Jupyter 的主要区别:Colab 每次会话重新分配 Kernel(环境不持久,需要重新安装包);文件存储在 Google Drive;资源有使用限制。生产级工作仍推荐本地 JupyterLab 或自托管 JupyterHub。
Jupyter 的通信架构
浏览器(前端) Kernel(后端进程)
│ │
│ ── 执行代码请求(ZeroMQ) ──► │
│ │ 执行 Python 代码
│ ◄── 执行结果(stdout/图表) ── │
│ │
│ ── 内省请求(Tab 补全) ──────►│
│ ◄── 补全候选列表 ──────────── │
│ │
多个 Notebook 可连接同一 Kernel(共享状态)
关闭浏览器 ≠ 关闭 Kernel(进程仍在运行)
Notebook 的最佳实践原则
保持线性可执行(Linear Executability)
Notebook 的最终状态应该支持"从头到尾顺序执行所有单元格得到相同结果"。即使在开发过程中乱序执行是正常的,完成分析后必须通过 Kernel → Restart & Run All 验证整个 Notebook 的可复现性。这是分享给他人或提交给团队的基本要求。
单元格要有单一职责
一个单元格只做一件事:加载数据的单元格不应该同时清洗数据;绘图的单元格不应该同时计算统计量。单一职责让每个单元格的输出有明确意义,也方便调试时精确定位问题。一个良好的 Notebook 中,每个 code cell 通常 5-20 行代码。
用 Markdown 单元格解释"为什么"
代码说明了"做什么"(What),Markdown 单元格应该解释"为什么"(Why)和"发现了什么"(Finding)。在关键分析步骤前加 Markdown 说明假设和动机;在关键输出后加 Markdown 解读结果的含义。这让 Notebook 成为真正可读的报告。
何时用 Notebook,何时用脚本
Notebook 适合:探索性分析、数据可视化报告、交互式演示、学习和实验。普通 .py 脚本适合:生产代码、定时任务、可重复调用的函数和模块、复杂的命令行工具。当 Notebook 中出现需要被其他代码 import 的功能时,应该将其提取为 .py 模块。
常见错误:把所有代码放进 Notebook
Notebook 擅长交互式分析,但不适合所有场景。以下情况应该使用普通 .py 文件:需要 import 的工具函数(如数据处理工具库)、长期运行的脚本(如数据管道)、需要单元测试的业务逻辑代码。将 Notebook 和 .py 文件混合使用是正确的工程实践:Notebook 做分析和可视化,.py 文件写可复用的模块,Notebook 中 import 这些模块。
Jupyter 的局限性与替代方案
版本控制困难
Notebook 的 JSON 格式包含大量输出和元数据,直接提交到 git 会产生巨大的 diff,难以 code review。解决方案:① 使用 nbstripout 自动清除输出后再提交(git hook);② 使用 Jupytext 将 .ipynb 转为 .py 格式同步版本控制;③ 使用 ReviewNB 等专门的 Notebook diff 工具。但即使有这些工具,Notebook 的版本控制体验仍不如纯代码文件。
调试体验受限
Notebook 不支持传统 IDE 的断点调试(虽然有 %debug magic,但体验不如 PyCharm/VS Code)。复杂逻辑的调试通常需要大量 print 语句。对于需要频繁调试的代码,建议先在 .py 文件中用 IDE 调试通过,再移植到 Notebook。
性能监控盲区
Notebook 中很难做系统级性能分析(CPU/内存/GPU 占用)。虽然有 %timeit 和 %memit,但无法像 cProfile 那样生成完整的性能火焰图。对于性能敏感的代码,应该在普通 Python 环境中用专业工具分析。
现代替代方案
VS Code Jupyter 扩展:在 VS Code 中原生支持 .ipynb,结合了 IDE 的调试能力和 Notebook 的交互性,是目前体验最好的方案。Google Colab:云端 Notebook,免费 GPU,适合学习和小规模实验,但网络依赖强。Databricks Notebook:企业级,支持协作编辑和大规模数据处理。Deepnote:现代化的协作 Notebook 平台,类似 Notion + Jupyter。
Jupyter 生态的工具链选择
nbconvert:Notebook 导出的核心工具
nbconvert 可以将 .ipynb 文件转换为 HTML、PDF(需要 LaTeX)、Python 脚本、Markdown、Slides(演示文稿)等格式。命令示例:
jupyter nbconvert --to html report.ipynb 生成可分享的 HTML 报告,所有输出和图表都内嵌其中,无需 Python 环境即可查看。这是数据分析结果分享的最常用方式。papermill:参数化执行 Notebook
papermill 允许在命令行传入参数来执行 Notebook,适合批量运行:
papermill analysis.ipynb output_jan.ipynb -p month 2026-01。用于定时任务(每月自动生成月报)、CI/CD 中的自动化分析、同一分析流程对不同数据集重复执行。与 nbconvert 配合可以实现"参数化执行 + 自动导出 HTML 报告"的完整自动化流水线。
本章小结
本章核心要点
- 文学化编程理念:Jupyter 实践了 Donald Knuth 的文学化编程思想——代码、输出、文字说明混合在一个文档中,形成完整可读的叙事链条。这是它与传统脚本的根本区别。
- .ipynb 文件格式:本质是 JSON,包含 cells 数组(每个 cell 有 cell_type、source、outputs)和 metadata(kernelspec 信息)。可被 git 版本控制,但需要 nbstripout 清除输出才能得到干净的 diff。
- Kernel 的角色:Kernel 是独立的编程语言进程,通过 WebSocket 与浏览器通信。关闭浏览器不会停止 Kernel;所有 cell 共享同一 Kernel 的内存状态;乱序执行会导致状态混乱,需要定期 Restart & Run All。
- 生态系统:Jupyter Notebook(经典)、JupyterLab(现代 IDE 风格)、JupyterHub(多用户服务器)、nbconvert(导出工具)、Google Colab(云端版本)。日常开发推荐 JupyterLab,教学演示用经典 Notebook,团队用 JupyterHub。
- 核心使用场景:数据探索与分析(最主要)、机器学习实验、学术报告复现、教学演示。不适合用于生产服务代码、长期运行的脚本(用普通 .py 文件)。