
如果你平时和 Python 打交道很难完全绕开 Jupyter Notebook/JupyterLab 这两个名字。我 2015 年第一次用 IPython Notebook 写实验记录后来一路看着它改名、升级变成现在几乎每个数据分析师都会打开的 Jupyter 生态。很多刚上手的人会把它们当成同一个东西其实这中间既有延续也有很明显的差异而日常使用中那些让人抓狂的报错很多也不是代码问题而是出在环境、目录、内核这类“看起来无关”的地方。这篇文章不做官方文档的复读把我这几年在 Notebook 和 JupyterLab 上反复踩过的坑合并成一份实战笔记重点讲清楚四件事安装配置时常见的 SSL 和构建报错该怎么处理侧边栏标题总览到底怎么调出来单元格和目录的使用逻辑是什么以及当你遇到“无法打开、无法运行代码”时应该从哪条线开始排查。适合刚装好 Anaconda 的新手也适合已经写了几个月但总觉得哪里不顺手的人。1. 先分清 Jupyter Notebook 和 JupyterLab不是替代关系而是两种工作方式1.1 前端、内核、文档三个不能被混为一谈的概念很多人分不清 Notebook 和 Lab是因为打开后满屏都是单元格看起来差不多。实际上 Jupyter 生态里存在三个层次前端界面、内核、文档格式。文档格式都是.ipynb内核也是同一套 Python、R、Julia 进程真正变的是前端界面。Notebook 是早期的单体界面一个页面只能专注一个文档顶部菜单、工具栏、单元格从上到下排开结构简单学习成本低。JupyterLab 是后来重新设计的“集成开发环境式”界面在同一个窗口里可以并排打开多个 notebook、终端、文本文件、图像窗口还能拖拽分栏。我自己的感受是如果你只是临时算个数、做个小演示Notebook 足够但只要开始把 Jupyter 当日常主力工具你会慢慢被 Lab 的多标签布局吸引因为同一个项目里代码、文档、终端同时摊开不用反复切窗口。另一个容易忽略的点是启动入口。Anaconda 装完后开始菜单里既有 Jupyter Notebook 也有 JupyterLab很多人以为要分别安装其实它们共享同一套内核和配置。你完全可以今天用jupyter notebook打开明天用jupyter lab打开看到的是同一个目录、同一批 notebook 文件。1.2 选型建议不同场景用不同前端如果你带着数据科学任务从零开始我的建议是直接上 JupyterLab同时保留 Notebook 作为备选。并不是说 Notebook 过时而是 Lab 在文件管理、多文档操作、扩展支持上更接近现代工具。官方也把新功能的开发重点放在 Lab 上边缘情况修复和插件生态都更新得勤快。我做一个简化对照方便不同使用习惯的人快速判断判断维度Jupyter NotebookJupyterLab单文档写作体验简洁、直观、无干扰窗口面板丰富需要适应拖拽多文件并排基本做不到天然支持分栏超好用内置终端不提供可以直接打开终端省去来回切侧边栏大纲需要第三方目录扩展内置 TOC点开就有插件安装方式nbextensions 体系labextension/扩展管理器体系适合场景新手入门、快速记笔记常态化开发、项目综合管理不过要注意Notebook 时代的很多经典扩展比如jupyter_contrib_nbextensions是为 Notebook 做的并不能直接用于 JupyterLab。不少人都在这上面翻过车按教程装好打开 Lab 却找不到任何变化。这个我在第 3 章会专门说。2. 安装配置避坑SSL、subprocess 和内核混乱问题2.1 用 conda 独立环境代替裸装包先治本在讲具体报错之前我最想强调一个习惯不要把所有包都往 base 环境里堆。很多 Jupyter 报错表面上是“启动失败”“无法运行代码”根子其实是不同项目的依赖搅在一起今天升级一个包明天另一个库就不兼容。我现在的标准做法是每类任务创建一个干净环境。比如做课程演示和快速实验我通常会这样初始化conda create -n lab python3.11 -y conda activate lab conda install -c conda-forge jupyterlab -y conda install -n lab ipykernel -y这里每一步都是有目的的。conda create隔离出独立 Pythonconda install从 conda-forge 通道装 Lab而不是用 pip 裸装因为 pip 在 Windows 上经常需要现场编译ipykernel则是让 Jupyter 能识别这个环境的关键少了它你即使在终端里conda activate lab打开 notebook 后用的还是别的内核。注册内核是另一个常被跳过但至关重要的动作python -m ipykernel install --user --namelab --display-name Python (lab)执行完可以用jupyter kernelspec list查看你会看到多了一个名为 lab 的内核。这一步做完JupyterLab 的启动器里才会出现 “Python (lab)” 这个选项。我遇到过不少“环境里明明装了 pandasnotebook 里却 import 不到”的情况十有八九是内核没注册notebook 实际跑的是另一套 Python。2.2 Windows 11 下配置 JupyterLab 提示 SSL ASN1 错误是什么情况这个话题几乎是搜索热词级别的了。报错信息大概长这样ssl.SSLError: [SSL] ASN1: not enough data有的版本还会在文字里带ca-certificates、certificate verify failed之类的上下文。好多人看到 “SSL” 就以为要配置证书或代理其实在 conda 环境里遇到这个大多数是环境内部组件版本错位。原因说起来并不神秘。conda 在升级某个环境时可能会更新openssl或者ca-certificates但 Python 自己编译时依赖的 ssl 模块版本没有同步或者环境里有旧版证书链导致在建立 HTTPS 连接时解析证书失败。Windows 11 上更常见的场景是你创建了一个新环境里面默认的 openssl 版本比较新而conda、pip或jupyter在拉取远程源时内部使用的 SSL 库和证书路径对不上。我按自己的经验整理过一套解决顺序你不需要全做但顺序很重要conda update -n base conda -c conda-forge -y conda activate lab conda update --all -y conda install -c conda-forge openssl ca-certificates -y先更新 base 的 conda 本身再更新当前环境的全部包最后单独强制装一次openssl和ca-certificates。多数情况下到这一步重启终端再执行jupyter lab就不会再报 ASN1 错误。如果还不行检查一下系统环境变量里有没有手填过SSL_CERT_FILE或REQUESTS_CA_BUNDLE这类变量一旦指向过期证书文件会让 Python 忽略系统证书库造成一样的表现。这里特别提醒网上有些帖子会让人直接关掉 SSL 校验比如设置pip config set global.trusted-host或者改环境变量跳过验证。这在临时环境里也许能跑但本质是掩盖问题之后会有更隐蔽的证书错误不建议长期使用。2.3 pip 安装扩展时报 subprocess-exited-with-error别急着重装搜索词里还有一个高频错误error: subprocess-exited-with-error。它通常出现在你用 pip 安装某个 Jupyter 扩展或 Python 包时下载完成、进入构建阶段后立即退出终端能看到类似 “Getting requirements to build wheel ... error” 的字样。新手最容易犯的错误是反复卸载重装同一个包其实问题根本不在包本身。现在 pip 安装源码包默认会用 PEP 517 的隔离构建流程很多包在构建阶段需要调用编译器。Windows 上最常见的是缺少 Microsoft C Build ToolsLinux 上常见的是缺少python3-dev、gccmacOS 上则是 Xcode Command Line Tools 未安装完整。我给你的排查思路是分三步走第一能用 conda 装的优先用 conda例如conda install -c conda-forge jupyter_contrib_nbextensions -y它会直接拉预编译好的二进制不需要在你的机器上碰编译器这是省时间最明显的一条路。第二确实要用 pip先升级构建工具链python -m pip install --upgrade pip setuptools wheel然后重新安装并在命令里加上--no-cache-dir避免缓存了损坏的源码包。第三如果依然失败不要盲目用最新版本。某些源码包在特定 Python 版本下有兼容性问题可以尝试指定旧一点的版本安装或者加--no-build-isolation参数跳过 PEP 517 隔离让安装过程复用当前环境已有的编译工具。这个参数不是银弹但能在找不到编译头文件时给出更真实的提示方便你判断是缺依赖还是包本身的问题。3. 日常工作流目录侧边栏、单元格操作和魔术命令3.1 侧边栏如何显示标题总览先说结论“侧边栏怎么显示标题总览”是很多人第一次接触 Jupyter 的高级功能时问的问题。先说结论JupyterLab 直接打开左侧栏的“目录”图标就行不需要额外插件老版 Jupyter Notebook 需要装一个 Table of Contents 扩展两个前端的大纲都来自 Markdown 单元格里的标题标记。在 JupyterLab 里只要打开任意.ipynb文件点左上角侧边栏的目录图标右边就会出现带层级的大纲。但这个功能有个前提你的标题必须写在 Markdown 单元格里用#、##、###表示不能只是用代码注释或普通文本。很多人以为写了# 标题就会出现在目录结果不显示就是因为那个单元格还是 Code 类型按Esc后按M把单元格切换成 Markdown再运行一次大纲就出来了。对于 Classic Notebook我推荐走jupyter_contrib_nbextensions路线。安装方式conda install -c conda-forge jupyter_contrib_nbextensions -y jupyter contrib nbextension install --user jupyter nbextension enable toc2/main安装完成后打开 notebook顶部菜单会出现 Nbextensions 选项在里面勾选 Table of Contents侧边栏或悬浮窗口就能看到标题总览。这里有个细节个别 Windows 环境下即使安装成功浏览器里也不显示 Nbextensions 菜单通常是因为 notebook 版本太新或浏览器缓存问题。我建议装完后重启 jupyter 服务并用无痕窗口重新打开一次。为什么标题总览如此重要因为 notebook 是“线性记录”几十个单元格一路滑下去想回头找某段结论非常痛苦。有目录之后长文档的定位效率会提升非常明显尤其是每周复盘实验、给别人演示分析流程时相当于给笔记加了一套索引。3.2 单元格操作快捷键每天节省半小时的细节标题总览解决的是“找得到”单元格快捷键解决的是“改得快”。Jupyter 的操作模式分成命令模式和编辑模式两者最直观的区别是编辑模式下单元格里有一个闪烁光标可以打字命令模式下单元格边框是蓝色按键对应各种操作。我最常用的组织方法可以浓缩成一句口诀Enter进编辑Esc回命令ShiftEnter运行并到下一个单元格。日常还会用到几组不复杂但极其顺手的快捷键快捷键作用使用频率ShiftEnter运行当前单元格光标跳到下一个几乎每次CtrlEnter运行当前单元格光标不移动反复试参数时AltEnter运行并在下方插入新单元格逐步推进时Esc后按A/B在上方/下方插入单元格高频Esc后按D D删除当前单元格高频Esc后按Z撤销删除救命用Esc后按M/Y切换 Markdown / Code写文档时Esc后按Shift↑/↓多选批量删除或移动整理长 notebook 时如果你把 JupyterLab 当主力还可以在 Settings → Keyboard Shortcuts 里自定义快捷键。我有一个小习惯把“运行当前单元格并向下插入”绑到CtrlEnter用起来比默认顺手很多适合想一边跑结果一边补注释的流程。快捷键不值得背完先把 ShiftEnter、A/B、D D、M/Y 用到形成肌肉记忆效率就已经肉眼可见提升。3.3 魔术命令装了三年没用的隐藏功能除了界面操作Jupyter 底层继承自 IPython 的魔术命令也很值得用。它们以%开头能直接嵌入单元格解决很多“本来要写十几行 Python 才能做”的事。我最常用的一套是这样%timeit测量单行代码执行时间自动跑多次取最短值比手写time.time()靠谱得多。在单元格开头用双百分号%%timeit还能计时整个单元格。%run xxx.py把外部 Python 脚本在当前内核里执行相当于把脚本内容塞进 notebook还共享当前变量。做代码评审时我经常把同事给的.py脚本用%run拉进来跑不用复制粘贴。%load xxx.py把外部文件内容加载进单元格方便边看边改。%env查看或设置环境变量比如%env MY_KEY123在 notebook 里管理临时配置很好用。%matplotlib inline让 matplotlib 图形直接显示在输出区域。新版本里用%matplotlib widget还能得到可交互的缩放图形。!pip install xxx感叹号开头表示执行系统命令很多教程会让你打开终端装包其实在 notebook 里直接用!pip install也行但那是在当前内核对应 Python 环境里安装注意别和自己激活的 conda 环境错位。魔术命令还有一个隐藏入口在单元格里输入%magic会弹出完整帮助文档。我看过不少写了两三年 notebook 的人从没用过%timeit通篇手写计时逻辑后面很容易被“看起来运行很快、实际卡很久”的假象骗到。4. 扩展和内核管理真正把 JupyterLab 变成开发环境的两个关键4.1 JupyterLab 扩展的安装方式和适量原则Jupyter 生态的扩展体系经历过几次变化很多人还按老教程执行jupyter labextension install xxx结果在新版本里报错。以 JupyterLab 4.x 为例大部分扩展已经可以通过左侧的 Extension Manager 图形化安装命令行的推荐方式是先激活你的环境再用 conda 或 pipconda install -c conda-forge jupyterlab-git -y conda install -c conda-forge jupyterlab-lsp -y conda install -c conda-forge python-lsp-server -y第一行是 Git 集成第二三行是语言服务器协议装上后能在 notebook 里获得跳转定义、悬停提示这类 IDE 功能。从实际体验来说我建议扩展数量克制一点最少主义优先目录内置、Git 集成、LSP 就够覆盖日常开发。装太多花哨主题和预览插件会让启动速度变慢还容易互相冲突。有一个很多人踩过的坑安装了某个扩展后JupyterLab 无法启动进度条卡在 Building 阶段。这时候不用急着卸载整个环境可以删除对应的扩展目录或者启动时加--disable-check暂时绕过检查再进入界面卸载问题扩展。另外JupyterLab 和 Notebook 的扩展体系根本不互通你在 Lab 里安装jupyter_contrib_nbextensions不会对 Lab 界面有任何效果它只作用于经典 Notebook。4.2 内核管理为什么换了 conda 环境notebook 里依然没有这个包这是搜索词里和“报 red 无法运行代码”并行的核心问题明明在终端里conda activate myenv之后再启动 Jupyter 了为什么 notebook 里仍然ModuleNotFoundError本质原因是Jupyter 内核不一定等同于你的终端 Python。启动 Jupyter 时它读取的是 kernelspec 配置每个 kernelspec 指向一个特定的解释器路径。你只是激活了 myenv却没有把 myenv 注册给 Jupyter它自然不会出现在内核列表中。解决办法很简单在目标环境中执行一次注册conda activate myenv python -m ipykernel install --user --namemyenv --display-name Python (myenv)执行完重启 JupyterLab在 Launcher 里就能看到 “Python (myenv)” 的新内核选项。验证当前 notebook 到底在用哪个 Python可以在单元格里运行import sys print(sys.executable)输出的路径会直接暴露内核指向。如果你运行出来的路径是/anaconda3/bin/python而你明明打算用 myenv那说明你打开 notebook 的那一刻选错了内核或者压根没注册成功。这个检查手段是我排查一切“代码无法运行”类问题的第一板斧。4.3 notebook 与 .py 脚本的双向转换Jupyter 项目最终总得沉淀成可维护的脚本或报告。我最常用的方式是把 notebook 转成.py在代码评审阶段发给同事看 diff比直接发.ipynb干净得多jupyter nbconvert --to script my_notebook.ipynb反向操作也有用。别人给你一个.py脚本你想进 notebook 里逐步运行、边跑边加注释可以用jupyter nbconvert --to notebook --execute sample.py --output sample.ipynb这条命令会把脚本内容转成 notebook 并自动执行一遍生成的.ipynb可以直接打开查看每个步骤的输出。我自己在整理教程或者把旧的实验脚本转成可复现文档时经常这样操作比手动复制粘贴单元格省下几十倍时间。5. 高频错误排查速查从“打不开”到“代码跑不了”的完整处置5.1 典型症状、原因和解决思路对照表我平时最常被问到的问题集中在几个症状里。把这些现象汇总成一张速查表遇到问题可以直接对应查看症状可能原因优先尝试启动 JupyterLab 后页面空白扩展冲突或缓存损坏清浏览器缓存删除~/.jupyter/lab/workspaces后重启双击.ipynb发现只是文件没有进入交互页没有启动 Jupyter 服务先在终端运行jupyter lab再从网页里打开文件打开后提示 Kernel error 或 Dead kernel内核指向的 Python 环境异常在单元格打印sys.executable确认重启 kernel按 ShiftEnter 后代码一直不执行内核未连接或卡死点 Kernel → Restart看终端输出日志端口被占用提示 address already in use上一次 Jupyter 进程未退出找到并结束占用 8888 的进程或jupyter lab --port8899安装目录插件后不生效Notebook/Lab 扩展体系混用确认你打开的是经典 Notebook并重启服务页面能开但 import 不到刚装的包内核不是当前 conda 环境注册目标环境为内核再开启新 notebook其中“按 ShiftEnter 代码不跑”应该是最让人崩溃的。我的排查路线不分先后先看两个地方右上角内核图标是空心还是实心终端里有没有 kernel 启动日志。如果内核图标变成空心或显示 “No Kernel”最快的方式是选择 Kernel → Restart如果重启后立刻又死掉多半是内核解释器本身有动态库加载问题这时候去终端手动敲python -c import flask之类的包看看能不能导入能帮助定位是不是 Python 环境坏了。5.2 侧边栏目录不显示的特殊情况刚才说过JupyterLab 的 TOC 是内置功能但偶尔也有点不出来的时候。一种常见场景是你只打开了一个空白 Launcher 页面没打开任何 notebook所以 TOC 面板显示“无匹配的标题”。这既不是 bug也不是没装好只要新建 notebook 并敲入一两个 Markdown 标题右侧大纲会立即出现。另一种情况是用老版 Notebook 时按教程装了 nbextensions但 TOC 按钮不见。我遇到过一次 Windows 下jupyter nbextension enable toc2/main显示成功浏览器依然没变化最后发现是浏览器缓存了旧页面。解决方法是重启 Jupyter用无痕窗口重新访问一次或者在终端执行jupyter nbextension list查看toc2是否在 enabled 列表里。只要列表里存在基本就是前端缓存或刷新时机的问题不是安装失败。5.3 我对环境的最终配置习惯和保持稳定的一点经验上面这些方法很多都是我栽过跟头之后才总结出来的。比如有一阵子我的 base 环境因为实验装了很多包conda update --all之后某个依赖升级直接把 notebook 的内核搞崩了连着两周反复出现 Kernel error。后来我把实验迁移到独立环境base 几乎不动这个问题基本绝迹。给新手朋友一个保守策略如果你没有把握不要在已经跑通 Jupyter 的环境里频繁执行conda update --all。需要新包时优先用 conda 安装必须用 pip 时先确认当前激活的是哪个环境。我见过太多案例是培训现场 pip 装包看起来装成功了重启后全消失最后发现是因为 pip 和 conda 指向了不同 Python。确保 notebook 稳定运行的最小验证动作是三步用sys.executable确认内核路径在单元格里确认版本号然后上传一份真实数据跑通入口函数。只要这两点清晰绝大部分“明明什么也没改、突然就坏了”的问题都能在五分钟内定位。我做过的另一个小习惯是给每个 notebook 文件在开头建一个“环境信息”单元格写清楚用它属于哪个 conda 环境、依赖了哪几个关键包版本。这个习惯看起来不痛不痒但当 notebook 写完后隔两个星期甚至三个月需要重跑时价值会突然放大——你不需要再靠猜去复现当初的运行环境了。实际上这篇文章里所有弯路汇总起来核心也就一件小事让 Jupyter 跑在你清楚知道的那个 Python 上用你清楚掌握内化过的交互方式去操作它。目录、扩展、快捷键、内核排查都是为这个目标服务的。如果你刚起步先顺手打开 JupyterLab 点一下左侧的 TOC 图标确认目录能用再新建一个环境跑一遍ipykernel install之后踩坑的概率不会太高。