跳转至

P2-10.3 把笔记本整理成可重新运行的记录

Section ID: P2-10.3 Version: v2026.09.15

已保存文档与执行状态

Jupyter Notebook 文件是扩展名为 .ipynb 的 JSON 文档。nbformat 文档说明,笔记本包含单元列表和元数据,单元可以有输入和输出。Jupyter 架构文档也把笔记本描述为共同保存代码、输出和 Markdown 说明的文档。

应区分代码、已保存输出和正在运行的状态。

flowchart TB
  A["笔记本文件<br/>.ipynb 文档"]
  B["Markdown 单元<br/>问题与说明"]
  C["代码单元<br/>Python 代码"]
  D["已保存输出<br/>数值、表、图表、错误"]
  E["内核内存<br/>变量与导入状态"]
  A --> B
  A --> C
  A --> D
  C -. "执行" .-> E
  E -. "生成输出" .-> D

代码和部分输出可以留在笔记本文件中。变量与导入状态位于运行中的内核内存里,重启内核会清除这些状态。磁盘文件与已安装包是另一回事;如果远程虚拟机本身被删除,只存在于该机器上的文件和安装状态也可能消失。

因此,仅保存笔记本还不够,还要检查保存后的文档能否重新运行。

清除输出与重启内核

清空画面与重置内存是不同的操作。下表以笔记本已保存、继续使用同一文件系统为前提。

操作 代码与说明 画面输出 变量与导入状态 磁盘文件
只清除输出 保留 清除 保留 保留
只重启内核 保留 可能保留 重置 保留
重启内核后运行全部 保留 按执行结果更新 按代码顺序生成 代码可能读取或修改

仅重启内核,并不意味着包和文件也变成全新环境。删除 Colab 远程 VM 并重新分配,是范围更大的重置;只存在于旧 VM 中的文件与安装状态也可能消失。

从准备到解释

适合学习的笔记本应能从上到下阅读和执行。

flowchart TB
  A["目的"]
  B["设置与导入"]
  C["准备数据"]
  D["计算"]
  E["查看输出"]
  F["记录解释"]
  G["重启内核并运行全部"]
  H["无错误且输出与解释一致?"]
  I["保存"]
  A --> B --> C --> D --> E --> F --> G --> H
  H -->|是| I
  H -->|否:修改| B

先写下要确认的问题,再导入所需包、准备数据并执行计算,查看结果后记录解释。

顺序混乱后,再次打开笔记本时,就容易忘记为什么做这项计算、用了什么数据、结果代表什么。

目的与数据范围

在笔记本开头,先说明目的,再放代码。

例如:“本笔记本计算一组小型分数数据的平均值和方差,比较数据的中心与离散程度。”

不断增加单元会让笔记本很快变长。缺少目的时,实验容易分散,结果所说明的问题也会模糊。

在目的单元中简要记录以下内容:

项目 原因
要确认的问题 避免实验分散
使用的数据 明确结果的范围
预期输出 确定观察对象
不涉及的内容 避免笔记本过度膨胀

如果追加不同目的的实验,应分别记录标题与输入条件。

准备包

把所需包的安装方法和导入放在计算之前。缺少 NumPy 的 Python 笔记本环境可以使用 %pip install numpy。%pip 是面向当前内核环境的 IPython 命令,不是普通 Python 脚本语法。

下面的准备单元导入 NumPy 并输出版本。输出因环境而异,应记录实际使用的版本。

import numpy as np
print(np.__version__)

输入数据

使用文件时,除了路径,还需要来源与准备方法。保存 data/scores.csv 字符串并不会同时保存文件本身。

输入类型 记录内容
小型示例 实际数值与含义
本地文件 文件和文件夹位置、运行工作目录
远程文件 下载来源、版本或核对日期
私人存储文件 连接方法与访问权限

下面是五名学生的百分制分数。赋值语句没有输出,它为后面的计算单元准备 scores。

scores = [82, 75, 45, 90, 61]

输出与解释

分数总和为 353,共五名学生,所以平均值为 70.6。下面的单元把含义标签与数值一起输出。

print("mean score:", sum(scores) / len(scores))

输出为 mean score: 70.6。下方可以写“五名学生的平均分为 70.6,最低分为 45”。数据变化时,应同时更新输出与解释。

设置单元的执行顺序

不同单元给同一个名称赋值时,以最后执行的赋值为准。第一个单元把学习率设为 0.1。

learning_rate = 0.1

第二个单元把它改为 0.01。

learning_rate = 0.01

检查单元输出当前值。

print(learning_rate)

按照第一单元、第二单元、检查单元执行,结果是 0.01;按照第二、第一、检查单元执行,结果是 0.1。把最终设置集中到一个单元,可以减少文档顺序与执行顺序混淆。

重要的笔记本可以这样检查:

  1. 整理不必要的临时单元,保留必要的准备。
  2. 重启 Python 内核。
  3. 从第一个单元运行到最后一个。
  4. 检查是否有错误,以及输出是否与说明一致。
  5. 保存核对后的代码、输出和解释。

随机数的起始状态

AI 和统计练习使用随机数进行抽样或初始化。下面的代码用种子 42 创建生成器,从五个值中不放回地抽取三个。检验环境的输出是 [50 10 40]。

1
2
3
4
5
import numpy as np

rng = np.random.default_rng(seed=42)
sample = rng.choice([10, 20, 30, 40, 50], size=3, replace=False)
print(sample)

种子可以理解为重新生成相同随机序列的起始值。并非每次练习都必须固定种子,但希望重现结果时,应记录它。

种子不能解决所有复现问题。包版本、环境、硬件和并行执行方式都可能影响结果。只重跑抽样步骤时,同一个生成器的状态已向前推进,结果可能不同。需要从创建生成器的语句重新运行,才能回到相同的起始状态。

分享前的准备

Colab FAQ 说明,文本、代码、输出和评论等笔记本内容可以共享,但虚拟机、运行时文件和已安装库不会随之共享。

分享 Colab 笔记本前,应检查:

检查事项 原因
必要的包安装单元 接收方运行时可能缺包
数据准备方法 运行时文件可能不会共享
Drive 访问权限 对方可能无法访问私人文件
能否从上到下执行 检查隐藏状态依赖
输出是否过时 已保存输出可能与当前代码不一致

何时把代码移到脚本

从笔记本开始的代码往往越来越长,之后可能更适合放入 .py 脚本。

出现以下信号时,可以考虑分离:

信号 含义
多个单元重复相同代码 可以提取函数
单元顺序经常混乱 脚本的执行顺序可能更可靠
每次执行相同预处理 可以提取函数或模块
其他笔记本也使用相同代码 可能需要公共 .py 文件
需要自动执行 脚本可能更合适

可以采用以下组织方式:

flowchart TB
  A["笔记本探索"]
  B["把重复计算提取为函数"]
  C["模块文件<br/>保存公共函数"]
  D["在笔记本中导入<br/>比较与解释"]
  E["在脚本中导入<br/>执行固定任务"]
  A --> B --> C
  C --> D
  C --> E

把公共计算放在模块中,在笔记本里管理输入与结果解释。

案例:被删除的准备单元

假设五个分数的平均值已正常显示,随后删除了创建 scores 的准备单元。在同一个内核中只重跑平均值单元,仍会得到 70.6,因为变量还在。

重启后,平均值单元会因缺少 scores 而产生 NameError。应恢复准备单元并从上到下运行。仅有保存的输出,不能证明当前代码能重新执行。

可运行的记录示例

下面的笔记本依次包含目的、输入与标准、计算、输出和解释。它只使用 Python 标准功能,不需要外部文件或安装包。下载后可在 Jupyter 中打开,也可通过 Colab 的上传笔记本功能打开。

分数与选择标准实验笔记本

默认分数是 [82, 75, 45, 90, 61],标准为 60。运行全部单元会输出:

1
2
3
4
count: 5
mean: 70.6
threshold: 60
selected: [82, 75, 90, 61]

把输入单元中的标准改为 80,并重跑计算和输出,平均值仍为 70.6,选择结果变为 [82, 90]。把最后一个分数改为 100,平均值变为 78.4。清空分数列表时,计算单元会按设计产生 ValueError。发生错误后,即使旧输出单元仍在,也不能把它当作本次运行结果。

按修改后的条件更新解释,重启内核并运行全部单元。没有错误且输出与解释一致时,再保存笔记本。已保存输出是用于比较的记录,不能代替新的运行。

检查清单

  • 能否把有效的笔记本解释为可重新运行的记录?
  • 能否解释隐藏状态为何有问题?
  • 能否解释为何把设置和数据准备单元放在前面?
  • 能否说明重启后从上到下执行的重要性?
  • 笔记本开头是否有目的与范围?
  • 必要的导入和安装步骤是否在前面?
  • 是否说明输入数据来源?
  • 所有单元能否依次执行而不报错?
  • 输出下方是否记录解释?
  • 涉及随机性时,是否说明种子或可能的变化?
  • 分享 Colab 时,是否检查文件、包和权限?
  • 重复代码是否需要分离到函数或 .py 文件?
  • 能否解释复现需要相同的准备流程,而不只是同一个文件?

来源与参考资料

  • Project Jupyter, Architecture, Jupyter Documentation,确认日期:2026-09-15。用于确认 notebook document 会把 code、output 和 markdown notes 一起保存。
  • Project Jupyter, The Jupyter Notebook Format, nbformat documentation,确认日期:2026-09-15。用于确认 .ipynb 文件是包含 cell list、metadata、cell inputs 与 outputs 的 JSON-based document。
  • Google, Google Colab FAQ, Google Colab,确认日期:2026-09-15。作为说明 Colab 共享时 notebook 内容与 runtime state 是分开的依据。
  • NumPy Developers, Random Generator, 核对日期:2026-09-15。生成器、种子、状态与跨版本复现限制的依据。