
用 Jupyter 写分析代码这件事我从 Notebook 时代一直用到 Lab 时代算下来也有好几年了。期间踩过的坑大概率也是你现在正遇到的装完发现默认保存路径不对、内核连不上、目录插件装不上、莫名奇妙地报permissionerror: [errno 13] permission denied还有网页版登录入口到底在哪。这篇总结不是官方文档的翻译是我这些年实际使用 Notebook / Lab 的经验汇总。内容分几块先讲 Notebook 和 Lab 怎么选、单元格思维怎么转再讲安装配置接着是魔法命令和快捷键然后是目录插件和界面调优后面是高频报错的排查思路最后聊一点工作流层面的长期建议。新手可以按顺序读已经用了一阵子的直接跳到第 5 章照着查问题就行。1. 先想清楚Notebook 和 Lab 到底选哪个1.1 两者定位的差异别用错了工具Jupyter Notebook 是最早走进大众视野的交互式笔记本界面一个页面里就是一个个单元格代码、Markdown、图表混排跑数据分析特别顺手。JupyterLab 是后来的集成工作台在同一个窗口里可以并排放笔记本、终端、文件浏览面板、文本编辑器本质上是一个 IDE 化的壳子。我的建议很直接如果你是从零开始、没有历史包袱直接装 JupyterLab因为它还在持续迭代功能覆盖 Notebook 的绝大部分如果你已经习惯了 Notebook 的操作路径也不必强迫自己迁移老界面依然能正常生存。实际工作中很常见的组合是JupyterLab 作为日常入口里面也可以用 Notebook 视图打开同一个文件两种模式随时切换没必要站队。从使用场景看Lab 多出来的文件管理、多标签、终端集成只有在处理多文件项目时才有明显优势。单独做一次探索性分析、画两张图Notebook 完全够用。所以这里的“选哪个”其实不是二选一而是“日常入口选 Lab旧文件照样能开”。1.2 从“脚本思维”切换到“单元格思维”写 .py 脚本时大脑默认是“从上到下顺序执行”而 Jupyter 是“每个单元格独立执行变量在全局内核里共享”。这个差异是第一道坎。我见过很多刚接触的人犯一个经典的错误前一个单元格定义了 df后一个单元格直接引用运行顺序一乱就报 NameError。Jupyter 的本质是保留了一个活的 Python 进程所有赋值都在这个进程里堆积。这意味着两件事一是你要主动维护“运行顺序”这个状态二是当你发现结果不对时第一反应应该是 Kernel - Restart Run All把环境彻底重置而不是在烂摊子上继续打补丁。养成这个习惯之后很多“奇怪的结果”能少一半。判断一个 notebook 是不是健康就看它能不能从头到尾一次跑通。凡是“我手动点到第三个单元格就能出结果”的 notebook都欠一次 Restart Run All。2. 安装与基础配置先花十分钟把环境理顺2.1 用什么方式安装最省心安装方式我推荐这么选如果你还没装 Python 环境直接装 Miniconda然后用 conda 建独立环境如果你已经有 Python 环境只是想在现有环境里加一个 Jupyter用 pip 装就行。conda create -n jupyter_env python3.11 conda activate jupyter_env pip install jupyterlab notebook或者直接pip install jupyterlab notebook装完启动命令是两个jupyter lab和jupyter notebook两个命令对应两套界面底层服务其实是同一套。这里有个很多人忽略的点不要用 conda 和 pip 混着装同一包。比如用 conda 创建环境、再用 pip 装 pandas很容易装出新旧两个版本互相干扰。原则是“一个环境尽量只用一种包管理器”要么 pip 装一切要么 conda 装一切。装好以后建议先做一次冒烟测试启动jupyter lab随便建一个笔记本跑print(ok)确认基础链路没问题再往里面装各种东西。很多人后续报错都是“环境装了太多东西根本不知道是哪一步留下的雷”。2.2 配置文件在哪怎么改变默认保存路径Jupyter 的配置目录默认在用户目录下的.jupyter文件夹里。第一次需要生成模板jupyter notebook --generate-config jupyter server --generate-config生成后会得到jupyter_notebook_config.py和jupyter_server_config.py。JupyterLab 用的是后者Notebook 用的是前者实际新版两个都会读。默认保存路径是最常被问的。想改默认目录在配置文件里写# 给 Lab 用 c.ServerApp.root_dir /home/you/work_notes # 旧版 Notebook 用的是 NotebookApp.key # c.NotebookApp.notebook_dir D:\\work_notes改完重启服务再打开页面默认目录就变了。注意 Windows 下字符串里的反斜杠要写成两个或者干脆写正斜杠。如果你只是偶尔一次想换个目录启动不需要改配置jupyter lab --notebook-dir/path/to/your/folder优先级上命令行参数覆盖配置文件。这里还要提一个排查定位的好命令jupyter --paths它会列出当前生效的配置目录、数据目录、运行时目录每个字段都有优先顺序。当你发现改了配置文件却不生效多半是改了一个不用的 config dir——比如系统级和用户级配置并存时你改的是比较小的那个。先用--paths确认你到底在改哪个文件。2.3 设置访问密码网页版登录入口不再迷路Jupyter 默认启动时会打印一串 token打开网页版登录入口时需要填 token 才能进入。很多新手第一次启动时没注意终端里那行地址点开浏览器发现要密码人直接懵了。最简单的办法是用命令生成密码jupyter notebook password连续输入两次密码它会自动写入jupyter_server_config.json把 token 模式“降级”成密码模式。之后访问地址就是你的IP:8888页面底部输入密码就行不再需要翻终端日志找 token。如果你更偏爱 token 模式每次启动时把终端里的 token 复制下来备用也行但体验上终究麻烦一些。默认配置下服务只监听127.0.0.1本机访问最安全。需要局域网内其他机器访问时再考虑修改监听地址这一步放到第 5 章详细说。顺便提一句密码设置这件事不要觉得无所谓很多人把 Jupyter 当成“自己电脑上的玩具”等到某天发现别人能打开你的内核执行命令才追悔莫及。3. 魔法命令和快捷键每天都能用到的效率点3.1 魔法命令比想象中更能省事魔法命令是 Jupyter 最有特色的功能。行级魔法命令以%开头只对当前一行生效单元级魔法命令以%%开头对整个单元格生效。我用得最多的有这么几个%time和%timeit前者跑一次看耗时后者自动多次取平均评估代码性能必用。遇到“这段代码怎么这么慢”的疑问先给关键行加一个%timeit心里就有数了。%who/%whos列出当前内核里所有变量%whos还会带类型和大小。写长笔记本时对“全局变量失控”特别管用隔几节用一次能看清你到底污染了多少命名空间。%run script.py把另一个 .py 文件作为脚本在当前内核里执行适合把已经成型的模块临时拉进来跑。%load把文件内容加载到单元格方便先看再运行。%matplotlib inline老版本必写的一行让图表直接嵌在输出区。新版 Jupyter 默认就是这个行为可写可不写写了也不报错。%%time单元级计时适合整个单元格都很慢的场景。%%writefile 文件名.py把单元格内容写成 .py 文件做代码导出很顺手。%%bash不切终端临时在单元格里执行 shell 命令比如看文件、压缩打包。还有一个很多人不知道的命令%lsmagic会列出所有可用的魔法命令忘了什么命令时先敲它。想了解具体用法时直接在单元格里写命令名?就能弹出帮助文档。这个“对象?查看签名/文档”的机制是 Jupyter 的通用操作别只会用help()。试过之后你就会发现魔法命令真正的作用不是炫技而是让你少在“终端”和“浏览器”之间来回切换。尤其%%writefile和%%bash组合起来等于把你的 notebook 变成了一个轻量级的运维台。3.2 快捷键少碰几次鼠标就值了Jupyter 核心是两种模式命令模式单元格边框高亮按 Esc 进入和编辑模式光标在文本框内按 Enter 进入。大部分值得记的快捷键都在命令模式下。我把日常最常用的列一张表给刚接触的人贴出来快捷键作用ShiftEnter运行当前单元格并跳到下一个AltEnter运行并新建一个单元格A / B在上方/下方插入单元格DD删除当前单元格Z撤销删除M / Y单元格切成 Markdown / CodeShiftTab查看函数签名与文档Tab代码补全F查找与替换C / X / V复制 / 剪切 / 粘贴单元格习惯之后分析流程基本变成Esc - A/B 新建 - M/Y 切类型 - ShiftEnter 执行鼠标只是偶尔用来选个范围。你还可以打开设置面板把某些快捷键改成自己熟悉的方式。我自己的经验是刚开始不用背全部快捷键先记住 ShiftEnter 和 A/B 这两个一周后自然就会扩展。硬背不如多用。快捷键这个东西属于“用一次就赚一次”一旦手指形成记忆比任何插件提升都明显。4. 加上目录、补全和界面优化从“能用”变成“好用”4.1 目录到底怎么加两个方案都给你搜索热度最高的“为 Jupyter Notebook 添加目录”其实分两种情况。如果你用 JupyterLab新版本自带大纲面板View - Show Table of Contents展开后左侧面板就出现目录点击跳转。这个功能免安装但只对正确使用 Markdown 标题#、##、###的单元格有效。所以写长 notebook 的第一步永远是给大段说明加标题层级而不是指望有什么工具能自动理解你的文字结构。如果你还在用经典 Jupyter Notebook 界面需要装扩展pip install jupyter_contrib_nbextensions jupyter contrib nbextension install --user装完在 Notebook 页面的 Nbextensions 标签里勾选 Table of Contents (2)。这样每页开头会自动生成一个带序号的目录还能折叠。这个扩展我用了很多年稳定性没什么问题。装 nbextensions 时有个小坑安装后如果页面里没出现 Nbextensions 标签检查是不是新版 Jupyter 默认停用了这类扩展。可以在启动命令里加参数或者在jupyter_notebook_config.py里显式加载。这个问题在第 5 章会详细讲这里先记住关键词“显式加载”。4.2 几个值得装的插件和一条美化路线还是分 Lab 和 Notebook 两套来说。JupyterLab 从 4.x 开始支持扩展左侧拼图图标就是 Extensions 面板直接在扩展管理器里搜装即可经典 Notebook 依然走 nbextensions。我实际保留下来并且每天在用的有这些autopep8Notebook/ BlackLab 扩展一键把代码格式标准化提交前必点。Execute Time在每个单元格右下角显示运行耗时优化长 notebook 时很有用。Variable Inspector侧边栏实时看变量值调试跨单元格的 bug 时省不少事。Collapsible Headings标题可折叠长文档导航更清爽。jupyterlab-gitLab 里的 Git 面板对比、提交都可视化了。主题类深色主题确实护眼但个人建议字体优先配置成等宽字体加 14 号代码区阅读感会好很多。一条重要的经验插件不是越多越好。每装一个插件都让启动变慢一点点出问题时也多了变量。我的原则是“功能先用原生的不够了再上插件”像目录、补全这些原生已经覆盖的就别再叠一层。装插件前先在文档里搜一下说不定官方早就做了。5. 高频报错与排查记录不能只会跑还要会救5.1 permissionerror: [errno 13] permission denied这个错误出现得莫名其妙但八成是“当前进程没权限写某个目录或文件”。我遇到的典型场景主要有这么几个。一是启动目录选在了受保护位置。比如 Windows 下直接把根目录 C:\ 或 Program Files 当成工作目录保存时就会撞 PermissionError。解决方式是用--notebook-dir切换到一个你有完整权限的目录或者放到用户目录下。别 root 一时爽后面全是泪。二是 Linux 下用 sudo 安装软件后顺手把某些项目也放到了 /root 或 /var 下然后用普通用户启动 Jupyter结果读文件没问题、一写就报错。先看属主和权限位ls -l /路径/文件如果是 root 所有用chown把目录交给当前用户或改用有权限的普通用户运行 Jupyter。这个排查步骤也是最容易被新手跳过的一步——他们宁愿重装一遍软件也不愿意看一眼权限位。三是 Docker 或云盘同步目录。Docker 挂载卷经常出现宿主机目录权限和容器内 UID 不匹配表现为写入失败Windows 的 OneDrive 目录偶尔会因为同步状态锁定文件。前者把挂载目录的权限位放宽松调试时chmod -R 755甚至 777 都可以后者换个本地磁盘目录即可。排查顺序建议是先确认报错文件路径 - 检查目录权限位 - 检查当前用户对目录的可写性 - 再考虑是不是同步软件锁文件。95% 的情况前两步就能定位。5.2 内核连不上或者内核启动失败“连接内核失败”是一个大类的统称实际内核可能根本没起来。排查套路如下。先用命令看一下系统认识哪些内核jupyter kernelspec list再看启动日志通常终端里会带着 Kernel 的 stderr 输出报错信息直接指向具体原因比如依赖缺失、ipykernel 版本不兼容。最常见的场景你在 conda 环境 A 里装了 Jupyter又在环境 B 里想用 B 的 Python却发现内核列表里只有环境 A 的。正确做法是在环境 B 里把 ipykernel 注册给当前 Jupyterconda activate myenv_B pip install ipykernel python -m ipykernel install --user --name myenv_B --display-name Python (myenv_B)重启 Jupyter内核选择列表里就会出现Python (myenv_B)。这个命令的本质是把一个环境的信息写到 kernelspec 里理解这一点遇到内核不显示就不会慌。它不复制任何文件只是告诉 Jupyter“这个内核在哪、用哪个 Python 启动”。如果内核一直报 ipykernel 相关错误升级一下 ipykernel 再重装内核即可pip install --upgrade ipykernel经过这一套我遇到的内核问题 90% 都能解决。剩下那 10%多半是 conda 环境本身坏了直接重建环境比硬修快得多。5.3 token 和局域网访问怎么配前面提到网页版登录入口需要 token 的问题这里展开远程访问的配置。注意一点默认服务绑定 127.0.0.1只有本机能访问这是安全设计不是 bug。如果需要局域网内别的机器访问可以启动时传参jupyter lab --ServerApp.ip0.0.0.0 --ServerApp.port88880.0.0.0 表示监听所有网卡地址端口按需改。这样同网段的其他设备就可以通过http://你的局域网IP:8888登录。前提是设好密码否则等于把整个内核暴露给网络非常危险。更稳妥的思路是先用密码登录再配合系统防火墙只放行可信 IP。我个人极不建议把公网 IP 直接绑到 Jupyter 上除非你很清楚自己在做什么并且做好了访问控制。很多安全事件就是“默认配置 公网暴露”造成的。记住Jupyter 的默认绑定 127.0.0.1 不是限制是保护。5.4 默认保存路径改了不生效这个场景在第 2.2 节提过一句这里再说一个常见原因你同时存在多个配置目录。操作系统级、用户级、conda 环境自己的配置目录优先级不同jupyter --paths --json会按优先级列出。当你发现有多个配置文件时记住“优先级高的先生效”直接改排在最前面的那个用户级配置文件即可。另外如果你用jupyter lab命令启动配置文件应该写c.ServerApp.root_dir如果你坚持用jupyter notebook命令新版也会兼容读 ServerApp 字段但部分旧版本需要写成c.NotebookApp.notebook_dir。建议打开配置文件搜一下关键词别凭记忆改。很多人改完不生效就是因为字段名写错或者写进了被注释的行里。还有个容易被忽略的点如果你是通过桌面快捷方式启动 Jupyter快捷方式的“起始位置”也会影响默认目录这种情况即使配置文件对了启动目录还是老路径。检查快捷方式的起始位置字段把它改成你希望默认打开的工作目录即可。6. 工作流层面的几个长期建议6.1 用 nbconvert 和脚本化任务脱离开界面Jupyter 是给人交互用的不是给机器跑的。如果哪天你想让 notebook 定时执行或批量运行第一反应不应该是开着浏览器挂着而是把代码转成 .pyjupyter nbconvert --to script 你的文件.ipynb转换出来的脚本会保留所有代码单元格并按顺序拼接Markdown 说明会变成注释可以直接交给 cron 或计划任务调用。另一个思路是 nbconvert 直接执行 notebook 并把结果写到新文件jupyter nbconvert --to notebook --execute --inplace 你的文件.ipynb这一步对数据日报这类场景特别好用改完数据源后跑一遍输出结果就留在文件里再配合邮件发送就是一套简单的自动化报表体系。6.2 版本管理别忽略清理输出.ipynb 本质是一个 JSON 文件里面包含代码、输出、元数据。直接提交 git 会造成两个问题diff 极难读而且输出中的大块 HTML、图表对象会让仓库膨胀。推荐工具 nbstripout它可以过滤掉输出内容再提交pip install nbstripout nbstripout --install它会自动给当前仓库加 filter 配置之后每次git add都会自动剥离输出。需要查看原始输出时用本地副本即可。如果你的团队协作重建议再加一条约定每个 notebook 顶部放一个“环境说明”单元格写清楚 Python 版本、依赖清单、跑通日期。这一行字在三个月后回看时价值远超任何注释。再补充一点把 notebooks 和代码目录分层管理。我的习惯是 notebook 放一个 notebooks/ 目录正式代码放 src/ 目录两个目录建立依赖关系但避免在 notebook 里堆太多业务逻辑。这样当 notebook 越来越臃肿时抽代码到 src 里的成本是可控的。6.3 环境即项目用 conda 环境锁住可复现性最后给一个我自己的小习惯每一个独立项目一个独立 conda 环境。环境名直接带项目名比如 proj_sales、proj_nlp。这么做的好处是每个项目的依赖哪怕冲突互相不干扰。项目收尾时导出清单conda env export environment.yaml pip freeze requirements.txt把这两个文件放进仓库别人 clone 下来就能重建环境。环境重建时conda 的 environment.yaml 保真度更高pip freeze 适合快速铺相同版本。如果项目里出现“昨天能跑今天报错”先别看代码先看环境清单是否有变动。排查顺序永远是环境 - 依赖 - 代码这个顺序能帮你把排查时间从半天压缩到半小时。我个人在实际操作中的体会是Jupyter 本身并不复杂真正的差距在习惯。把启动目录固定下来、把密码设好、把内核环境管住、把输出清理做好这四件事做完使用体验能上一个大台阶。最后再分享一个小技巧新建 notebook 的第一件事不是写代码而是给单元格命名并写一行注释说明这段内容的用途。等你三个月后打开一堆 notebook 找东西时就知道这个习惯有多救命了。