前言
Jupyter Notebook 常被当成「网页版的 Python 解释器」,但它真正的价值不在运行代码,而在把代码、运行结果和说明文字放在同一个文档里。也正因为如此,它有一类别的工具没有的 陷阱:单元格可以任意顺序执行,而界面上看起来一切正常,于是「同一个笔记本在不同人手里 跑出不同结果」这种事会真的发生。本文分两部分:前半讲基础操作(单元格、快捷键、内核、 装包),后半讲「文本用法」,也就是 Markdown 单元格怎么写文字、写公式、搭结构,最后专门 讲执行顺序这个坑。
说明两点。第一,Jupyter 是第三方项目,需要单独安装;它的界面和快捷键会随版本变化,具体快捷键以 Jupyter 官方文档为准。第二,Python 2.7 已于 2020 年 1 月 1 日停止 维护,新建笔记本请一律使用 Python 3 内核。
一、Notebook 与内核是什么关系
先把一个结构讲清:一个打开的笔记本恰好连接着一个内核(kernel)。内核是真正执行 代码的后台进程——在 Python 笔记本里,它就是一个 Python 解释器。你按下运行,代码被 送到内核执行,结果再回传到页面显示。
这个关系带来两个重要后果:
- 内核状态独立于页面。官方文档说明,浏览器窗口关掉之后内核仍然可能活着,重新打开
同一个笔记本会重新连上它。也就是说,你看到的变量可能来自很久以前的某次执行。
- 重启内核会清空内存中的变量,但不会删除笔记本里保存的输出,也不会删除磁盘上的
文件。想验证「代码从头能不能跑通」,必须重启内核再从头执行。
二、三种单元格:code / markdown / raw
一个笔记本由若干单元格(cell)组成。官方文档明确写了有三种类型:
| 类型 | 作用 | 是否被执行 |
|---|
| code(代码) | 写可运行的代码 | 是,由内核执行 |
| markdown | 写说明文字,支持 Markdown 与 LaTeX 公式 | 不执行,只渲染 |
| raw | 原样保留的内容,导出时不加工 | 不执行 |
每个新建的单元格默认是 code 类型,可以在工具栏的下拉框里改,也可以用键盘快捷键改。 写代码用 code,写说明和公式用 markdown,需要原样透传的内容才用 raw。
三、最常用的键盘操作
官方文档特别提醒:先学会在「命令模式」和「编辑模式」之间切换。按回车进入编辑模式 (可以打字),按 Esc 回到命令模式(按键变成快捷键)。之后按这个顺序熟悉:
- 基本导航:回车、Shift+Enter 运行当前单元格。
- 保存:
s。 - 切换单元格类型:
y变成代码,m变成 Markdown,数字1~6设置 Markdown 标题
级别。
- 增删单元格:
a在上方插入,b在下方插入;x剪切,c复制,v粘贴;
连按两次d删除。
- 撤销:
z。 - 内核操作:
i连按两次中断内核,0连按两次重启内核。
其中Shift+Enter是最该先记住的:运行当前单元格并跳到下一个。刚上手时,很多人 不知道要先按回车进入编辑模式再打字,于是在命令模式下按字母,结果误触发了各种快捷键。
四、Markdown 单元格:文字、结构与公式
这是标题里「文本用法」的核心。Jupyter 的 markdown 单元格支持标准 Markdown 语法,并且支持用 LaTeX 写数学公式,由 MathJax 在浏览器里渲染——这是官方文档明确列出的能力。
标题、列表、表格、强调这些写法:
标题:行首一个井号是一级标题,两个井号是二级标题。
段落之间空一行。
- 列表项
- 另一项
**加粗**、*斜体*、`行内代码`
表格:
| 列 A | 列 B |
| --- | --- |
| 1 | 2 |数学公式有两种:行内公式夹在一对美元符号之间,独立成行的公式夹在一对双美元符号之间。
勾股定理写成 $a^2 + b^2 = c^2$ 是行内公式。
独立成行的公式:
$$
\int_0^1 x^2 \, dx = \frac{1}{3}
$$渲染之后,第一行里的公式会和文字排在一行,第二个公式会单独居中显示。要写多行对齐的 公式组,用aligned之类的环境,具体语法以 LaTeX 与 MathJax 的文档为准。
一个常见困惑:为什么我写了公式却没渲染?通常是因为这个单元格的类型还是 code,而 不是 markdown——code 单元格里的内容会被当成 Python 代码。切换到 markdown 再运行一次 即可。
五、装包与调用系统命令
在笔记本里装包,有两种形式:
# 适用于 Python 3.8+
# 方式一:魔术命令(推荐,绑定当前内核的解释器)
# %pip install requests
# 方式二:行首叹号调用系统命令(IPython 的 shell 转义)
# !pip install requests两者都能装,但推荐%pip:它明确作用于当前内核所用的解释器。用!pip时, 执行的是系统 PATH 里的那个 pip,如果内核跑在虚拟环境里,就可能出现「装成功了却 import 不到」的情况——包装到了另一个环境。这一点和上一节讲的「内核与解释器绑定」是 同一个道理。
同样地,任何以!开头的行都会被原样交给操作系统执行:
# 适用于 Python 3.8+
# !ls
# !pwd装完包之后,通常需要重启内核(或重新导入模块)才能看到新装的库。
六、执行顺序陷阱:为什么结果不可复现
这是 Jupyter 最需要警惕的地方。单元格的编号只表示创建顺序,不表示执行顺序。你 可以反复回头执行第 3 个单元格,也可以跳过第 2 个直接跑第 5 个。于是会出现:
- 图上的某个结果,依赖的是一个已经被删除或修改过的单元格。
- 你在第 10 个单元格删除了一个变量,但没重跑第 5 个,界面上却仍然显示第 5 个的旧输出。
- 别人打开你的笔记本,从头执行,结果和你屏幕上看到的不一样。
下面这张表对比「看起来对了」和「真的对了」:
| 行为 | 看起来对了 | 真的对了 |
|---|
| 只改了一个单元格 | 只看那个单元格的输出 | 从头到尾重跑一遍 |
| 有报错被跳过 | 忽略错误继续往下跑 | 先解决错误,再继续 |
| 删掉某段代码 | 界面还留着旧输出 | 重启内核后重跑确认 |
| 分享笔记本 | 直接发.ipynb | 先从头跑通,必要时清空输出 |
想要可复现,做法很朴素:重启内核,然后从头执行所有单元格,中间不能有报错。如果 一个笔记本重启后跑不通,那它就没有被真正验证过。
常见坑点
坑点 1:在命令模式下按字母想打字。
❌ 错误做法:
按 Esc 回到命令模式后,直接敲字母想输入文字,结果把单元格删了或换了类型✅ 正确做法:
先按回车进入编辑模式再打字;不确定当前模式时,看单元格边框的颜色坑点 2:markdown 单元格里写公式没渲染。
❌ 错误做法:
把公式直接写在 code 单元格里,运行后报语法错误✅ 正确做法:
把该单元格的类型切成 markdown 再运行,公式才会被 MathJax 渲染坑点 3:用!pip装包,结果 import 不到。
❌ 错误做法:
# 适用于 Python 3.8+
# !pip install requests
# import requests # ModuleNotFoundError,包装到了别的解释器✅ 正确做法:
# 适用于 Python 3.8+
# %pip install requests # 绑定当前内核的解释器
# import requests坑点 4:改完代码不重跑上游单元格。
❌ 错误做法:
只改了第 2 个单元格,却只看第 7 个单元格的旧输出✅ 正确做法:
改动后重启内核并从头执行,确认结果确实变了坑点 5:靠界面上的旧输出判断代码正确。
❌ 错误做法:
删掉了定义变量的单元格,界面还留着下游的旧输出,就以为程序没问题✅ 正确做法:
重启内核,从头执行;旧输出不等于当前代码的结果坑点 6:把笔记本当工程主目录。
❌ 错误做法:
把所有业务逻辑写在一堆单元格里,靠人工保证执行顺序✅ 正确做法:
# 适用于 Python 3.8+
# 逻辑放进 .py 模块,笔记本里只导入和展示
def process(rows):
return [r for r in rows if r is not None]坑点 7:在文件读写时不指定编码。
❌ 错误做法:
# 适用于 Python 3.8+
with open("data.txt") as f: # 跟随平台默认编码
text = f.read()✅ 正确做法:
# 适用于 Python 3.8+
with open("data.txt", encoding="utf-8") as f:
text = f.read()不同平台默认编码可能不同,显式写encoding更稳。
坑点 8:内核卡住时以为程序崩了。
❌ 错误做法:
遇到死循环,直接关掉浏览器窗口就以为任务结束了✅ 正确做法:
用「中断内核」停止当前执行;确认停了再继续,必要时重启内核关窗口不一定结束内核,它可能还在后台占着资源。
总结
| 需求 | 做法 |
|---|
| 运行当前单元格 | Shift+Enter |
| 在代码与文字间切换 | 单元格类型选 code / markdown |
| 写公式 | markdown 单元格里用 LaTeX |
| 装包 | %pip install,绑定当前内核 |
| 调用系统命令 | 行首! |
| 保证结果可复现 | 重启内核后从头执行一遍 |
| 沉淀为工程代码 | 逻辑移到.py文件 |
Jupyter 的长处和短处都来自同一件事:它是一个有状态的交互式文档。状态让「改一点看 一点」变得极快,也让「结果到底怎么来的」变得模糊。用好它的办法很简单——探索时尽管 乱序执行,交付前一定重启内核、从头跑通。