Chapter 05 / 10

单元格:Code、Markdown、Raw

深入理解三种单元格类型、执行顺序的陷阱,以及高效操作单元格的技巧

三种单元格类型

Jupyter Notebook 中有三种单元格,通过工具栏下拉菜单或快捷键切换:

类型快捷键用途
CodeY执行代码,显示运行结果
MarkdownM富文本说明,渲染后显示格式化内容
RawR原始内容,不执行也不渲染,供 nbconvert 使用

Code 单元格

Code 单元格是 Jupyter 的核心,用于输入和执行代码:

In [1]:
import math
x = 16
print(f"√{x} = {math.sqrt(x)}")
Out [1]:
√16 = 4.0

Code 单元格的特性

# 最后一个表达式自动显示(Out 输出)
x = 5
x * x   # Out [2]: 25,无需 print

# 如果不想显示,在末尾加分号
x * x;  # 不输出任何内容

输出类型

Code 单元格可以产生多种输出:

输出类型触发方式示例
标准输出print()文本流
返回值表达式(无分号)2 + 3Out[1]: 5
错误信息异常红色 Traceback
图表matplotlib 绘图内联图像
HTMLIPython.display.HTML()富文本
DataFrame 表格pandas DataFrame格式化表格

Markdown 单元格

Markdown 单元格用于写文档说明。双击已渲染的 Markdown 单元格可以进入编辑模式;按 Shift+Enter 渲染。

Markdown 单元格渲染效果
Markdown 单元格渲染后的效果:标题、加粗文字、有序列表,数学公式也能正确渲染

Markdown 常用语法速查

# 标题
# 一级标题
## 二级标题
### 三级标题

# 文字格式
**粗体**  *斜体*  ~~删除线~~  `行内代码`

# 列表
- 无序列表项 1
- 无序列表项 2
  - 嵌套列表

1. 有序列表项 1
2. 有序列表项 2

# 代码块
```python
print("Hello, World!")
```

# 表格
| 列1 | 列2 | 列3 |
|-----|-----|-----|
| A   | B   | C   |

# 链接与图片
[链接文字](https://example.com)
![图片描述](path/to/image.png)

执行顺序与 In/Out 编号

这是 Jupyter 中最容易造成混乱的地方。执行编号 [n] 代表全局执行顺序,不是单元格在文档中的位置。

# 单元格 A(位于顶部)
x = 10    # 先执行,In[1]

# 单元格 B(位于中间)
x = 20    # 后来修改,In[3]

# 单元格 C(位于底部)
print(x)  # In[2] 时输出 10,In[4] 时输出 20
DANGER 如果你多次修改并重新运行某个单元格,变量的值由最后一次执行决定,而不是文档从上到下的顺序。这是 Jupyter 最常见的 Bug 来源!定期使用 Kernel → Restart & Run All 确保结果一致。

单元格操作快捷键(命令模式)

先按 Esc 进入命令模式,然后:

A在当前单元格上方插入
B在当前单元格下方插入
D D删除当前单元格(按两次 D)
Z撤销删除
X剪切当前单元格
C复制当前单元格
V在下方粘贴单元格
↑ / ↓选中上/下一个单元格
Ctrl+↑/↓移动单元格
M切换为 Markdown 类型
Y切换为 Code 类型
Shift+M合并选中的单元格

Raw 单元格

Raw 单元格的内容既不会被执行,也不会被渲染。主要用于:

在日常使用中,Raw 单元格较少用到。

多选单元格

在命令模式下,按住 Shift 点击可以选中多个单元格,然后批量操作:

Code 单元格的高级功能

# 1. rich display — 显示 HTML、图片等富媒体
from IPython.display import display, HTML
display(HTML('<b style="color:red">红色粗体文字</b>'))

# 2. 显示多个输出(用 display() 函数)
import pandas as pd
df1 = pd.DataFrame({'A': [1,2], 'B': [3,4]})
df2 = pd.DataFrame({'X': [5,6], 'Y': [7,8]})
display(df1)
display(df2)  # 两个 DataFrame 都会显示,不只是最后一个

# 3. 用分号抑制最后一行的 Out 输出
2 + 3;  # 不显示 Out[n]: 5

# 4. _ 变量访问最近的输出
10 * 3   # Out[n]: 30
_ + 5    # 使用上一个 Out 的值:35
print() vs 自动输出的区别
print() 写入标准输出流(stdout),始终输出字符串文本,无论什么对象都转换为字符串形式。自动输出(最后一行表达式)调用对象的 __repr__ 或 _repr_html_ 方法,返回富文本。pandas DataFrame 的 _repr_html_ 生成 HTML 表格,所以在 Jupyter 中显示为美观的表格而非纯文本。任何自定义类都可以实现 _repr_html_ 来控制 Jupyter 中的显示效果。
单元格分割与合并
在编辑模式下,将光标放在要分割的位置,按 Ctrl+Shift+- 将单元格从光标处一分为二。在命令模式下,Shift 点击选中多个单元格,再按 Shift+M 合并为一个。注意:合并后无法自动分割回去(撤销 Z 只能撤销最近一次删除,不能撤销合并);分割时会在光标位置断开,确保光标位置正确再操作。
折叠与隐藏输出
当一个 cell 产生大量输出时,点击输出区域左侧的竖线可以折叠;再次点击展开;双击完全隐藏(只留一行高度)。在代码中也可以控制:在 cell 末尾加分号抑制表达式的 Out 输出;用 from IPython.display import clear_output; clear_output() 清除之前的输出(用于进度更新场景)。

Raw 单元格的实际用途

nbconvert 格式化指令
Raw 单元格的主要用途是向 nbconvert 传递格式化指令。例如,将 Notebook 导出为 reStructuredText 格式时,可以在 Raw 单元格中写 RST 指令。在 cell 的 metadata 中设置 format 字段(如 "text/restructuredtext"),nbconvert 会将该 cell 的内容原样包含在导出文件中。这是 Notebook 针对特定导出格式的高级功能,日常分析中很少用到。
临时禁用代码
将 code cell 改为 raw cell(快捷键 R)是暂时禁用一段代码的方式——既保留代码内容和格式,又不会被执行。这比注释代码更干净,保持代码高亮便于阅读。恢复时按 Y 切回 code 类型。但注意:nbstripout 工具不会清除 raw cell 的内容,raw cell 始终会保存在文件中。

单元格执行的深层机制

最后一行表达式自动输出
Code 单元格中,最后一行如果是一个表达式(不是赋值语句),Jupyter 会自动调用 repr() 将其展示为 Out[n]。这与 print() 不同:print() 总是输出字符串,Out[n] 调用对象的 __repr__ 方法,DataFrame 会显示为富文本表格,图表对象会直接渲染图像。如果最后一行以分号结尾(如 df.head();),则抑制 Out 输出。
非线性执行的隐患
当一个单元格被反复修改并重新执行时,每次执行都会更改全局变量状态。例如:cell_A 第一次定义 x=1,cell_B 使用 x,然后回到 cell_A 把 x 改为 99 并重新运行,此时 cell_B 的输出已经"过时"——它显示的是 x=1 时的结果,但当前内存 x=99。发布给他人的 Notebook 必须能从头到尾顺序执行得到相同结果。
Markdown 单元格的渲染时机
Markdown 单元格点击 Run 后立即渲染为富文本。双击会回到原始编辑模式;Shift+Enter 重新渲染。如果 LaTeX 公式没有正确渲染,通常是浏览器 MathJax 加载问题(离线时会失败),不是语法错误,等待页面加载完成或刷新即可。

本章小结

本章核心要点