如果你刚接触jupyter notebook,最典型的第一幕可能是这样:你装好 Anaconda,双击 Jupyter Notebook 图标,等待几秒后浏览器里弹出来一个目录列表;又或者你跟教程在终端里敲下jupyter notebook,结果系统直接提示“jupyter不是内部或外部命令,也不是可运行的程序”。这两种体验,随便遇到哪一个,都足够让新手产生一个念头:是不是我安装错了?
但真正的问题往往不是安装,而是对 Jupyter Notebook 的定位没有理解清楚。这个工具解决的并不是“把代码写出来”,而是把“代码、输出、过程记录、实验思路”放在同一个文件里,让一次性探索变成可回看的实验记录。这个转换一旦想明白,后面所有关于空白页、内核、环境、目录、保存的问题,都会有更清晰的排查方向。
这篇文章不打算把 Jupyter 的所有文档翻译一遍,而是围绕一个我见过很多次的现象来写:单次跑通 Notebook 很容易,但真正稳定地用它完成项目,难点从来都在环境、状态和工程习惯上。我会从它的核心工作方式讲起,再讲安装选型、最小可运行流程、常见排查,最后说清楚它适合什么、不适合什么。
1. 先搞清楚 Notebook 真正改变的是什么工作方式
1.1 它更像实验记录,而不是普通脚本
你在 PyCharm 或 VS Code 里写一个.py文件,本质上是在编辑一个完整的程序文件:写完之后整体运行,输出打在控制台,中间变量除非加print,否则很难看到。Jupyter Notebook 的差异在于,它把“代码”和“结果”按单元格组织,一个单元格执行完,输出直接跟在下方。
这个能力的价值,在做数据分析和早期探索时非常明显。你可以先加载数据,看一眼形状,再决定下一步怎么清洗;可以随时画一张图,确认特征分布是否合理;也可以在某个单元格里实验一种算法,不满意就重新执行,不用把整份文件从头跑一遍。
有人会说:这不过就是把打印输出的位置换了。但真正的变化不是输出位置,而是工作流。传统脚本是“编辑—运行—看结果—改代码—再运行”;Notebook 是“一边思考一边写单元格,每个单元格保存了一段可复现的中间过程”。后者更适合处理不确定的问题,也就是你一开始并不知道最终代码会长什么样的任务。
1.2 单元格执行顺序:代码不是永远从顶部开始运行
这是新手最容易踩的第一个坑,也是理解 Notebook 的关键。
Notebook 里的代码单元格并不强制要求从上到下依次执行。你可以先执行第三个单元格,再回去执行第一个;也可以把第二个单元格反复执行好几次;甚至可以删除某个中间单元格,然后继续运行后面的单元格。问题在于,每个单元格执行时都会改变内核里的变量状态,后执行的单元格会读取当前状态,而不是你眼睛看到的“文件顺序”里的状态。
举一个最简单的例子:
# 单元格 1 x = 2 # 单元格 2 x = x * 10 # 单元格 3 x = x + 5 print(x)如果连续按顺序执行完这三个单元格,输出是25。但如果你只重新执行第 3 个单元格,它会基于当前内核里的x值再+5。如果之前没执行过第 2 个单元格,输出可能完全不同。这种“状态残留”在变量多、运行顺序乱的时候,会制造出一种代码没问题的假象——因为某个单元格单独看起来是正确的,但它依赖了不在文件顺序里的旧变量。
实际落地时,我建议把每个单元格当成一个独立的“实验操作”来写:不要过度依赖前面的隐藏状态。如果你想让别人能复现你的结果,一定要做一次“重启内核并全部重新运行”,确认按顺序执行能得到一致输出。
1.3 输出和保存:文件里存的不仅是代码
另一个常见误解是:Notebook 保存了输出,所以“我已经把结果保存下来了”。
实际上,.ipynb文件里确实会保存代码单元格和输出结果,但这不代表这些输出是可依赖的正式结论。如果一个项目换了依赖版本、换了输入数据、或者内核重启后没有重新运行某一个单元格,你看到的旧输出可能已经和当前代码不一致。
所以,正确的做法不是信任文件里已经渲染出来的输出,而是信任“从干净内核开始、按顺序运行所有单元格”之后得到的结果。每次继续一份旧 Notebook 之前,先检查有没有已经“过期”的单元格;最稳妥的方式是重新执行一遍,再开始改代码。
2. 安装和选型:打开浏览器之前先确定这些选择
2.1 Anaconda、Miniconda 和 pip:各自的取舍
围绕 Jupyter 的安装问题,热搜词里反复出现“Anaconda jupyter notebook”和“jupyter notebook 安装”。这也说明多数人并不是在安装 Jupyter 本身,而是在选择一个 Python 环境管理方案。
简单整理一下差别:
| 方案 | 适合谁 | 优点 | 需要注意 |
|---|---|---|---|
| Anaconda | 数据分析和教学新手 | 自带 Python、conda、Jupyter、常用库,开箱即用 | 安装包大,预装内容多,更新过猛可能影响其他项目 |
| Miniconda | 想用 conda 管理环境但不想装一堆预置包的人 | 体积小,环境可控 | 需要自己安装项目和 Jupyter |
| pip | 已有 Python 环境,只想补一个编辑器 | 轻量,符合已有使用习惯 | 容易出现不同环境间包不互通的问题 |
没有绝对最优方案。如果你是第一次接触 Python 数据分析,并希望快速跑起来,Anaconda 确实能减少很多前置工作;但如果已经是开发者,只是偶尔想用 Notebook 做点分析,直接用pip install notebook可能更轻。
这里要提醒一句:不要一次性同时用 Anaconda、Miniconda、系统 Python、PyCharm 自带的 Python 做实验。多个 Python 环境并存本身不冲突,但如果你分不清当前终端激活的是哪个环境,就很容易出现“我明明装了包,Notebook 里却找不到”的情况。
2.2 Jupyter Notebook 和 JupyterLab,究竟差在哪
“jupyter notebook lab 区别”是搜索频率很高的词。其实理解起来不复杂:
- Jupyter Notebook是经典界面,文件列表、编辑区、输出区相对简单,一个窗口管理一个 notebook。
- JupyterLab是 Notebook 的“升级工作台”,支持多标签页、左右分栏、拖拽文件、内置终端、文本编辑器,还能同时打开多个 notebook 和
.py文件。
现在的 Jupyter 生态里,JupyterLab 基本是默认推荐的入口,但很多课程和旧文档仍然使用 Notebook 界面。两者底层的文件格式都是.ipynb,所以切换使用不会影响文件本身。
我的建议是:新用户直接使用 JupyterLab,它不会让你损失 Notebook 的核心体验,反而可以少装一个桌面客户端;如果某些教程明确让你启动旧版 Notebook 界面,也可以在启动命令里选择jupyter notebook,不影响学习。
2.3 工作目录与启动位置,决定了你打开的是哪个文件
很多新人会遇到一个困惑:双击 Jupyter 图标后,文件列表里看不到自己刚创建的文件夹。原因通常是:Jupyter 显示的是它启动时所在的工作目录,不是安装目录,也不是你最近打开过的目录。
在终端里进入你想工作的文件夹再启动,是最直接的方式:
cd D:/projects/notebook-demo jupyter notebook如果你用的是 Anaconda Navigator 里的图形界面入口,就需要在界面里设置启动目录,或者直接打开终端启动。JupyterLab 和 Notebook 界面顶部都有目录栏,可以点击进入其他文件夹,但每次启动时的根目录仍然是启动位置。
稳妥的做法是养成一个习惯:先决定项目放哪里,再在该目录下启动 Jupyter。不要让它随机跑到用户目录,不然最后你会得到一堆分散在系统各处的.ipynb文件。
3. 从零跑通一个最小可运行流程
3.1 环境准备与版本确认
不管用哪种安装方式,建议先检查版本是否可用:
python --version conda --version jupyter --version如果jupyter命令暂时不能用,可以用模块方式验证:
python -m jupyter notebook --version这个方法在 Windows 上尤其有用。很多时候终端敲不出jupyter,只是因为可执行文件没进 PATH,并不是没有安装成功。
Linux 或 macOS 下的环境创建,可以参考这样的步骤:
conda create -n jupyter-env python=3.9 conda activate jupyter-env pip install notebook jupyterlab如果你是 Windows 用户,安装 Anaconda 后建议从“Anaconda Prompt”或“Anaconda PowerShell”中启动,而不是直接用普通的 cmd。这能避免环境变量没刷新的问题。
3.2 新建 Notebook、写第一段代码、执行与保存
在 JupyterLab 或者 Notebook 界面中,点击New或+符号,选择 Python 3 内核,就会生成一个空的.ipynb文件。
在第一个单元格里写入:
print("hello jupyter")按Shift + Enter执行。你会在单元格下方看到输出。这一步如果没问题,说明安装链路已经打通。
保存时直接按Ctrl + S。.ipynb文件会保存当前代码和已经渲染出来的输出。你要养成的习惯是:重要实验节点,重新执行一遍再保存。不要保存一份“代码看起来对,实际没有重新验证过”的文件。
3.3 创建 .py 文件与导出脚本
有些同学用 Notebook 写代码时,会被“怎么创建.py文件”卡住。这里有两种常见理解:
一是你希望在一个 Notebook 项目里新建纯 Python 文件。在 JupyterLab 里,可以在文件夹面板右键,选择“New -> Python File”创建.py文件;在旧版 Notebook 界面里,可以新建一个 Text File,然后保存为.py后缀。
二是你想把 Notebook 里的代码导出成一个完整的.py脚本。典型做法是用 nbconvert:
jupyter nbconvert --to script your_notebook.ipynb执行后会在同目录生成一个.py文件。导出的脚本会把单元格转换为按顺序排列的 Python 代码,注释也会保留。这个功能很适合做项目收尾:你先在 Notebook 里完成探索,再导出一份干净脚本放进正式项目仓库。
3.4 切换目录和其他浏览器
“jupyter lab 启动后怎么切换目录”这个问题,本质上要先区分“临时切换”和“默认目录”。
- 临时切换:进入文件树,点击目标目录即可。
- 默认目录:希望每次启动都直接在某个目录,可以用参数指定:
jupyter notebook --notebook-dir=D:/projects/notebook-demo jupyter lab --notebook-dir=D:/projects/notebook-demo在 Windows 上,最快的方法是在目标文件夹的地址栏输入cmd,回车后会直接在该目录打开命令行,再执行jupyter notebook。
“如何在其他浏览器打开”的前提是服务已经启动。Jupyter 启动后会在控制台输出一个带 token 的 localhost 地址。你只需要把这段完整地址复制到想用的浏览器里打开即可,不一定非要改配置文件。如果确实要固定修改,可以用:
jupyter notebook --generate-config然后编辑用户目录下的.jupyter/jupyter_notebook_config.py,找到对应配置项按需修改。注意不同版本配置项名称略有差异,修改前先确认文档。
4. 从能跑到能用:内核、环境与工程习惯
4.1 内核、解释器与虚拟环境的关系
这是“能跑”和“能稳定跑”之间的关键分水岭。
在 Jupyter 里,每个 Notebook 默认对应一个内核。内核本质上就是运行你代码的 Python 解释器。你在终端里安装的包,只有在对应内核指向同一个环境时,Notebook 里才能 import 到。
常见的错乱是:用 Anaconda 的 base 环境启动 Jupyter,然后在 Notebook 里!pip install requests,看上去装成功了,但换到另一个 conda 环境创建的 notebook 里就导不进来。这是因为!pip默认装的是当前内核所在环境的包,不是你脑海中认为的“全局环境”。
如果你在多个 conda 环境间工作,一个更稳妥的方式是把每个环境的 ipykernel 注册到 Jupyter 里:
conda activate myenv pip install ipykernel python -m ipykernel install --user --name myenv --display-name "MyEnv"执行之后,在 Notebook 的内核切换菜单里就会出现MyEnv。这样你可以在同一个 JupyterLab 里,用不同内核处理不同项目。
只要记住一点:Notebook 左上角显示的内核,和你安装依赖的环境,必须是同一个。遇到ModuleNotFoundError,先检查这个,再谈其他。
4.2 Magic 命令、快捷键与常用扩展
Jupyter 里有一类以%开头的 Magic 命令,能在不写复杂代码的情况下完成常见操作:
%timeit sum(range(1000))%timeit会对语句执行多次计时,用来快速判断哪段代码更慢。
%matplotlib inline在 Notebook 中直接显示 matplotlib 图表,通常在使用 Jupyter 做可视化时需要。
在一个单元格开头使用%%bash,可以把整个单元格当作 shell 脚本运行:
%%bash echo "hello"这类命令不用贪多。只要记住%timeit、%matplotlib inline,平时就能省不少事。快捷键方面,最核心的是Shift + Enter运行并进入下一个单元格,Esc退出编辑模式后用A在上方插入单元格,B在下方插入单元格,M把单元格切换为 Markdown,Y切回代码。先把这几个用熟,效率会明显提升。
扩展插件可以增加功能,但没必要一开始就装很多。插件和 Jupyter 版本之间的兼容问题,会让排查难度显著上升。我建议入门阶段保持默认配置,遇到不够用的时候再按需装。
4.3 从单文件实验到模块化项目组织
Notebook 方便,但也不能让所有代码都堆在单元格里。当实验越做越大,建议把可复用逻辑抽到.py模块中,在 Notebook 里 import 进来:
my_project/ ├── notebook_demo.ipynb ├── data/ │ └── sample.csv ├── utils/ │ ├── __init__.py │ └── preprocess.py └── requirements.txt这样做的好处有两个。第一,函数经过测试后,不需要在每个 Notebook 里复制一份;第二,别人看项目时,可以通过utils/preprocess.py快速理解核心逻辑,而不是翻几十个单元格。
还要养成固定随机种子、固定依赖版本的习惯。Notebook 里使用了随机数的地方,在开头设置random.seed(42)或np.random.seed(42),能让实验更容易复现。依赖则用requirements.txt或environment.yml保存,避免半年后想复跑,连包版本都找不到。
5. 问题排查:空白页、命令不存在、路径混乱
5.1 Windows 打开空白页,先别急着重装
“Windows jupyter notebook 打开后空白”是一个出现频率非常高的搜索词。遇到这种情况,先不要卸载重装,按顺序检查。
第一步,看启动服务的终端窗口。Jupyter 启动时,终端会打印启动地址、token、内核连接信息。如果终端还在正常输出,说明服务本身可能已经起来了,问题更可能出在浏览器或端口。
第二步,把终端里显示的 localhost 地址复制到一个干净浏览器窗口。很多时候是因为浏览器缓存或旧标签页没有刷新,随便换一个新窗口,地址重打一次,问题就消失了。
第三步,换端口。默认端口是 8888,如果被其他程序占用,Jupyter 会自动切换或报错。你可以手动指定:
jupyter notebook --port=8889第四步,如果页面还是空白,再检查是不是网络环境或安全策略拦截了 localhost。某些公司电脑或受控系统会限制本地 Web 服务访问。这种情况不一定能在 Jupyter 端解决,需要找运维确认。
用排除法比反复重启要高效得多:先怀疑浏览器,再怀疑端口,最后才怀疑安装。
5.2 “jupyter 不是内部或外部命令”意味着什么
这条报错第一次出现时,很容易让人误以为安装失败了。实际上,多数时候只是命令所在的目录还没有被加入 PATH,或者当前终端没有激活对应的 conda 环境。
排查顺序:
where jupyter python -m jupyter notebookwhere jupyter能看系统是否能找到可执行文件;如果找不到,说明 PATH 里没有。用python -m jupyter notebook绕过 PATH 问题,看看安装是否存在。如果python -m能启动,说明包是装好的,只是命令入口没法直接调用。
解决方式有两条路:
- 在 Anaconda Prompt / 正确环境的终端里使用,而不是普通 cmd。
- 把对应环境下的
Scripts目录加到 PATH。这适合熟悉环境变量的人,不推荐新手为了省事去改系统 PATH,因为多个环境混在一起,后面很容易乱。
5.3 目录、权限、编码和资源占用
之前提过,Notebook 显示的是启动目录里的文件。如果出现“找不到文件”,往往是:
- 你还没有切换到文件所在目录。
- 文件名包含特殊字符或中文,在某些环境中可能导致显示异常。
- 权限不够,进程无法读取目录。
保存时报错,重点看目录是否可写。如果在系统盘的用户目录里通常没问题,但如果是 C 盘边缘目录或受控目录,可能会被系统拦截。
读取数据文件时,编码是常见坑。比如用 Jupyter 打开 CSV,中文乱码,就要显式指定编码:
import pandas as pd df = pd.read_csv("data/sample.csv", encoding="utf-8")如果文件本身是 GBK 编码,遇到报错可以尝试encoding="gbk"。这并不是 Jupyter 的问题,而是文本文件编码问题,但在 Notebook 里会经常遇到。
资源占用方面,一个容易忽略的点是:不用的内核不会自动关闭。多次点击“运行”或新建多个 Notebook 后,每个内核都会占用内存。如果机器内存小,做点稍大的数据操作就可能卡死。可以在 Jupyter 的管理界面里把不用的内核 Shutdown,而不是直接关浏览器标签页。
5.4 一个可复用的四层排查框架
把前面这些零散问题归纳一下,Jupyter 的故障排查基本是一条链路:
现象层 → 输入层 → 环境层 → 工具边界层具体对应关系:
| 层级 | 关注点 | 典型例子 |
|---|---|---|
| 现象层 | 有没有报错、有没有输出、页面是否卡住 | 空白页、无输出、内核崩溃 |
| 输入层 | 文件、路径、编码、数据是否符合预期 | CSV 乱码、目录找不到、文件名拼写错误 |
| 环境层 | 依赖、内核、虚拟环境、PATH 是否正确 | ModuleNotFoundError、jupyter 命令不存在 |
| 工具边界层 | 端口、浏览器、版本兼容、插件冲突 | 默认端口被占用、插件不兼容 |
排查时按这个顺序来,每检查一层,把截图或终端日志记录下来。不要跳过现象层直接去改环境,否则很容易把本来能运行的机器改得更乱。
6. 边界:哪些场景别用 Notebook
6.1 适合它的三类场景
第一类是数据分析探索。数据加载、清洗、可视化、建模全在一个文件里,输出和图形随手可见,对思路整理非常有帮助。
第二类是教学和分享。Notebook 能把文字、公式、代码、图表放在一起,作为教程或课程材料非常合适。读者可以边读边运行。
第三类是实验过程记录。在做一个需要反复试参数的任务时,Notebook 天然保留了中间的思考和执行痕迹,回看时比零散脚本更容易还原当时为什么这样做。
6.2 不建议它的三类场景
第一类是大规模代码项目。几百个单元格堆在一个文件里,函数互相引用,依赖顺序复杂,维护成本会很高。这类项目更适合模块化的.py项目结构。
第二类是线上服务或自动化任务。Notebook 本身是给人交互式使用设计的,不适合长期跑在服务器上提供接口。让 Jupyter 服务长期外网暴露还有安全风险,不建议在没有完整认证、网络隔离、运维监控的情况下这么做。
第三类是多人实时协作的正式代码库。Notebook 的.ipynb是 JSON 格式,实际多人并发改同一个文件时,冲突排查比.py文件麻烦很多。团队协作时,更适合把核心逻辑抽成普通 Python 模块,Notebook 只做调用和展示。
6.3 给长期使用者的三条工程化建议
如果已经决定把 Notebook 纳入日常工作流,我建议从最开始就定下三条纪律。
第一,保持 Notebook 小而清晰。一个 Notebook 只负责一个主题,做完就整理,不要把它变成所有想法的大杂烩。
第二,提交前执行一次干净的完整运行。我可以告诉你,Notebook 学习者最容易犯的错误不是代码写错,而是“部分单元格顺序不对,结果看起来也对了”。合并或分享前,先执行Kernel -> Restart & Run All,确保按顺序运行也能得到同样结果。
第三,用版本管理但不要被输出污染。如果你使用 Git 管理项目,可以配置工具或脚本,在提交前清理 Notebook 的输出。否则每次执行结果稍有不同,都会产生大量 diff,很难看出代码真正的变化。
注意:在团队里要建立一条明确规则:合并 Notebook 改动前,必须确认所有单元格能够从头到尾重新运行。只看到“有输出”并不代表结果可复现。
最后的建议
回到开头那个场景。如果你现在在 Windows 上装了 Anaconda,打开 Jupyter 却看到空白页,或者被提示“jupyter 不是内部命令”,不要把问题复杂化。先启动终端,确认服务有没有起来;再用浏览器打开终端里的地址;最后用四层排查框架逐层定位。
从更长远的角度看,Jupyter Notebook 值得我们花时间去掌握,不是因为它能让我们少敲几个快捷键,而是它把“尝试、犯错、记录、回看、复用”这个过程真正固化下来了。对所有从事数据分析、机器学习和教学工作的人来说,这套交互式工作方式的底层价值,不会因为换一个编辑器或者换一个框架而消失。
所以,下一步最该做的不是收藏更多教程,也不是再装一个扩展插件,而是打开一个 Notebook,把一份你已经熟悉的数据加载进来,先画出一张图,然后问自己一句:如果明天重开这个文件,我还能验证今天的每一步吗?这个问题,才会真正把你从“会打开 Notebook”推向“能驾驭 Notebook”。