ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Jupyter Notebook/Lab 核心技巧:从安装配置到高效调试实战

Jupyter Notebook/Lab 核心技巧:从安装配置到高效调试实战 很多人在用 Jupyter Notebook 和 JupyterLab 时其实只把它当成了一个带执行的草稿纸写一段代码按下 ShiftEnter看到结果完事。这个用法不能说错但远远低估了 Jupyter 家族能解决的问题。作为一个日常拿它写分析、做演示、甚至搭内部小工具的人我今天想把这些年踩过的坑和沉淀下来的技巧一次性梳理出来从安装环境、路径权限到长文档导航、魔法命令和调试器再到导出和分享的边界问题都尽量讲透。如果你是刚入门的小白这篇文章能帮你少走一半冤枉路如果你已经用了很久但总觉得卡手里面不少细节大概率是你没注意过的。核心关键词只有一个——Jupyter Notebook/Lab 使用技巧我把重心放在“实际按下键盘之后会发生什么”上尽量不谈空泛的概念。1. 别急着装完就跑安装、启动与路径选择里的坑1.1 用对安装方式才不糟蹋你的 Python 环境第一次按网上的教程装 Jupyter 时最常见的操作就是打开终端输入pip install jupyter然后等它慢慢装。如果用的是系统自带的 Python尤其是 macOS/Linux 上这一步很容易埋雷系统环境里已经有一堆依赖pip装的时候又不敢乱动权限最后要么装上去了启动报错要么把系统的 Python 搞乱。我的建议是优先用 Anaconda 或者 Miniconda 建一个独立环境再装。比如conda create -n jupyter_env python3.11 conda activate jupyter_env pip install jupyterlab notebook这样做的核心原因不是洁癖而是 Jupyter 的内核机制。Jupyter 本身只是一个 Web 前端真正跑代码的是一个“内核”要是一个笔记本文件记录的内核和你当前激活的环境对不上启动时最大的表现就是报错、无响应、或者找不到包。独立环境能让你随时重建、随时扔掉不会影响你干其他活。当然如果你对 conda 无感用python -m venv也一样python -m venv jupyter_venv source jupyter_venv/bin/activate # Windows 下是 Scripts\activate pip install notebook jupyterlab装完之后直接在终端敲jupyter lab或jupyter notebook浏览器会自动弹出。要是没弹出终端里会打印一个带 token 的 URL手动复制到浏览器即可这就涉及下面要说到的登录入口问题。1.2 启动失败和 PermissionError 究竟卡在哪热词里有个很典型的报错permissionerror:[errno 13] permission denied。我在各个群里见过不下三四十次大部分场景都是在 Linux 服务器或者 macOS 上敲了jupyter notebook结果提示这个错误一脸懵。这个错误的本意是“当前用户没有权限访问某个文件或目录”。在 Jupyter 语境下最常涉及两处一处是配置文件目录通常叫.jupyter在用户主目录下。Jupyter 启动时会往里面读写history.sqlite、runtime等文件。如果这个目录的属主不是你或者之前用sudo启动过导致文件属主变成了root后面再用普通用户启动就会撞上 PermissionError。另一处是运行时创建的runtime目录默认在~/.local/share/jupyter/runtime或者/tmp/jupyter-runtime附近。某些服务器会把/tmp权限锁得很紧或者挂载的/home分区有noexec/ 限制写入的选项也会导致类似报错。排查思路比直接给命令更重要。先找到 Jupyter 认为自己的工作目录在哪运行jupyter --config-dir jupyter --runtime-dir然后对照着看ls -ld ~/.jupyter ls -ld $(jupyter --runtime-dir)如果是属主问题直接sudo chown -R $USER:$USER ~/.jupyter如果是/tmp被限制了就显式指定一个可写的运行目录export JUPYTER_RUNTIME_DIR$HOME/.jupyter/runtime jupyter notebook同样配置目录也可以就近迁移export JUPYTER_CONFIG_DIR$HOME/.config/jupyter这套方法在服务器上尤其好用毕竟不是所有机器都让你随便sudo。1.3 默认保存路径和下载文件最终去哪了另一个高频热搜是“jupyter notebook 默认保存路径”和“使用 jupyter 下载的文件默认安置在哪”。先搞清楚一个概念在浏览器里点Download下载的.ipynb文件走的是浏览器自身的下载逻辑存到哪里由浏览器的设置决定跟 Jupyter 无关。所以有人发现默认下载到了~/Downloads那不是 Jupyter 管的。但是如果你在 notebook 里用 Python 代码写文件比如with open(out.txt, w, encodingutf-8) as f: f.write(hello)这个文件会出现在“当前工作目录”下也就是 notebook 文件所在的目录。因为 Jupyter 启动后会把 notebook 所在目录作为当前目录而open()的相对路径就是相对于这个目录的。那默认保存路径怎么改最干净的做法是在启动前就指定jupyter notebook --notebook-dir/path/to/your/projects可以把--notebook-dir写进启动目录的快捷方式或别名里alias jnjupyter notebook --notebook-dir$HOME/projects更一劳永逸的是修改配置文件jupyter notebook --generate-config打开生成的~/.jupyter/jupyter_notebook_config.py找到这一段# c.ServerApp.root_dir 改成你的目标目录c.ServerApp.root_dir /home/me/projects注意老版本里变量名可能是c.NotebookApp.notebook_dir新版本已经迁移到ServerApp。版本差异是这里最搞人的点遇到修改后不生效先查一下你现在装的版本和对应的配置项名。2. 在 Notebook 和 Lab 之间怎么选不是升级换代那么简单2.1 Notebook 的老派优雅与掣肘Jupyter Notebook也就是经典版的界面是“一个页面里上下排列多个单元格”虽然简单但用了很多年后你会很明显地感受到它的限制整个页面只有一个视图没法同时看两个 notebook每个文件单独占一个标签页一旦开得多标签页密密麻麻拖拽单元格换位置在单个文档里还可以跨文档基本叫天天不应。Notebook 的好处是它老插件生态成熟。jupyter_contrib_nbextensions里一大堆经典扩展比如代码折叠、目录、高亮选中的变量、自动格式化等等都只在 Notebook 界面里比较顺手。如果你的主力机器还在跑老项目那么新版 JupyterLab 往往无法直接复用这些 nbextensions。2.2 Lab 补齐了什么切换成本又有多高JupyterLab 从设计之初就奔着“集成开发环境”去文件列表在左边主区域可以开多个窗口支持拖拽布局同一个浏览器窗口里同时排两个笔记本毫无压力。它还统一了很多之前要单独装的东西多语言支持、命令面板CtrlShiftC 呼出以及内置的表格查看器、CSV 预览等。切换成本不是我一开始想得那么低。比如原先在 Notebook 里靠 nbextensions 开启的“目录”功能在 Lab 里需要单独装jupyterlab/toc新版本甚至已经内置为右侧的 Outline 按钮。还有一些自定义的 nbextensions 在 Lab 里完全不认只能等作者出 Lab 插件版本有的等了两三年都没消息。所以我的个人建议是如果你主要做数据分析不太依赖老插件直接上 Lab如果维护的是三年前的 notebook 文件而且经常要用老扩展那就老老实实继续用 Notebook或者两个都装用哪种界面取决于当时的任务。2.3 多标签、文件树、单元格拖拽实测在 Lab 里拖拽单元格比想象中顺手。你先在左侧文件树点击文件名打开两个 notebook然后在任意一个 notebook 里选中若干单元格Shift点击可以多选直接拖到另一个 notebook 的目标位置。这个操作在 Notebook 里是做不到的除非你 CtrlX、CtrlV 跨页面复制再手动修一下代码里的状态。文件树的支持也算一个决定性差异。在 Lab 里可以直接用右键菜单对文件做重命名、移动、新建文件夹甚至打开一个临时终端日常文件操作就省得跳出浏览器了。快捷键体系两个界面基本一致。熟悉的核心组合ShiftEnter运行单元格并选中/跳到下一个CtrlEnter只运行当前单元格A在上方插入B在下方插入D D连续按两次 D 删除单元格M进入 Markdown 状态Y切回 Code 状态我建议所有用户把这几个刻进肌肉记忆比点鼠标效率高出一个量级。3. 让目录树滚起来长文档导航方案实测3.1 装插件前先搞清你用的是哪个环境“为 jupyter notebook 添加目录”是永久热搜。很多人遇到的尴尬是明明在网上搜到pip install jupyter_contrib_nbextensions装完也执行了 enable但打开 Notebook 还是看不到目录。最常见原因是你装了插件 A但 Jupyter 跑的是另一个环境的内核。确认环境一致性最直接的方法which jupyter jupyter --version pip list | grep nbextensions确保这三者指向同一个 Python 环境。尤其是当你用 conda 激活了环境但终端里的jupyter还是指向另一个路径时插件安装到哪里去了根本说不清。这时候要么老老实实把jupyter重装到当前环境要么用python -m jupyter notebook来强制走当前解释器。3.2 两种主流目录插件配置与对比在 Notebook 界面主流方案是jupyter_contrib_nbextensions提供的Table of Contents (2)也叫toc2。安装过程pip install jupyter_contrib_nbextensions jupyter contrib nbextension install --user jupyter nbextension enable toc2/main装好后重启 Notebook在“Nbextensions”配置页面里找到Table of Contents (2)勾选上。它会视情况在工具栏上多一个目录按钮同时给 Markdown 标题生成锚点。在 Lab 界面新版默认自带 Outline入口在右侧侧边栏的书签图标下方。如果你用的版本比较老可以手动装pip install jupyterlab jupyter labextension install jupyterlab/toc对比一下两者体验功能Notebook toc2Lab Outline实时定位点击目录跳转点击目录跳转标题层级折叠支持支持跟随滚动高亮部分版本支持支持较好与代码块协作仅 Markdown 标题支持 Markdown 和代码单元格大纲拖拽调整窗口否是我自己的实测感受是如果你只是需要一个简单的导航Lab 自带 Outline 反而更干净但老牌 toc2 可以和“折叠代码”等 nbextensions 协同习惯后其实非常好用。3.3 目录/折叠/大纲的一体化用法光有目录还不够实际阅读体验要配合代码折叠。在 Notebook 里Codefolding是 nbextensions 里非常受欢迎的一个扩展点击代码单元格左侧的小箭头即可对函数体、类体或if块进行折叠。这个功能长 notebook 里特别有用尤其当你只关心某个函数的位置时折叠掉 80% 的代码配合目录整个文档的可视性会大幅提升。另外一个小技巧Markdown 标题顺序要及时更新。目录本身是读取 notebook 的元数据来生成的如果你在单元格里删改了很多标题位置最好先保存文件再刷新一下目录避免跳转目标错乱。在 toc2 里还有一个小齿轮可以设置“标题编号”、“超链接跳转”等选项。我一般会开启“标题编号”这样段落之间有层级感导出成 PDF 或者 HTML 时也更专业。在 Lab 里Outline 支持搜索过滤直接键入标题关键字可以快速定位到长文中某个章节。对于动不动几百个单元格的报告型 notebook这个功能我几乎每天都会用到。4. 魔法命令与交互模式真正提升日常效率的十来个玩法4.1 把时间测出来%time 和 %%time 的差别很多人不知道 Jupyter 里自带“魔法命令”以百分号开头的指令。最开始值得记住的是%time和%%time。区别很直接%time只测量这一行的代码耗时%%time测量整个单元格的耗时%time sum(range(10_000_000))%%time total 0 for i in range(10_000_000): total i使用场景是当你在两个写法之间犹豫时别靠猜跑一遍%%time比什么都有说服力。如果你想知道更精细的差异还有%%timeit它会自动把代码执行很多次然后取平均适合对微性能敏感的项目。4.2 自动重载模块、一键运行任意代码串在 notebook 里开发自己的 Python 模块时最痛苦的一件事是改了.py文件再重新导入模块不会自动更新。解决方案不是importlib.reload一遍遍手工来而是用内置的自动重载%load_ext autoreload %autoreload 2开了%autoreload 2之后只要.py文件的代码发生变化运行任意单元格前 Jupyter 会先自动重新加载这些模块。这几乎是本地开发一个包时的标配省掉的“重启内核”时间不计其数。注意%autoreload 1只对%aimport指定的模块生效一般不如 2 来得省心。还有一个很有用的命令是%run它可以运行一个 Python 脚本并把脚本执行后的命名空间留在当前内核里%run myscript.py如果你有一个生成的.py文件想看看里面的变量结果又不想复制粘贴这个命令非常合适。相反%load可以把一个文件内容直接加载到当前单元格%load myscript.py这适合你想拆解别人的脚本加载进来后手动调整再执行。4.3 魔改输出显示%config 与装饰器的结合Jupyter 的显示系统远比 print 丰富。我最常用的是IPython.displayfrom IPython.display import display, HTML, Markdown, Image, Video display(HTML(tabletrtdA/tdtdB/td/tr/table)) display(Markdown(### 这是一个三级标题)) display(Image(filenameplot.png))对于 DataFrameJupyter 会自动渲染成可滚动的表格但如果你希望控制 pandas 显示的行数和列数可以这样%config ZMQInteractiveShell.ast_node_interactivity all这是一个被低估的配置在普通 Python 里一行表达式只有最后一个会被输出而在 Jupyter 里加上这个配置后单元格内所有能求值的表达式都会显示出来不需要一个个写display。类似地可以限制 DataFrame 显示import pandas as pd pd.set_option(display.max_rows, 100) pd.set_option(display.max_columns, 50)还可以通过interact创建交互控件这是 IPython widgets 的入口。简单示例from ipywidgets import interact interact(x(-10, 10, 1)) def f(x): return x ** 2运行后会生成一个滑动条调节参数立即重新执行函数。这在做参数探索时很有用比如调整绘图窗口大小、过滤阈值等亲测能省大量“改参数重跑”的无聊循环。5. 排错和调代码那些让人抓狂的异常与诊断技巧5.1 内核死了别慌先查这四类问题在 Jupyter 里你可能会遇到Kernel Restarting或者“The kernel appears to have died”这类提示。内核崩了最直接的影响是之前定义的变量全部丢失只能重跑一遍。按照经验八成原因逃不开四种无限递归或死循环占满了 CPU 和内存。一次性分配超大数组比如numpy.arange(10**12)瞬间把内存打满。C 扩展段错误例如某个库底层用了 ctypes 且指针写坏。多线程/多进程管理不当比如在 fork 之后调用了某些非线程安全的库。应对手段是分级排查。先看任务管理器或top确认是不是内存爆了。如果只是死循环可以用菜单里的Interrupt Kernel快捷键是I I中断执行。如果已经完全卡死那就只能重启内核但注意重启前把还热乎的结果手动保存因为输出缓冲区不一定来得及写盘。5.2 调试器的三种打开姿势pdb、%debug、ipdb代码报错后最常见的动作是看 traceback然后一头扎进代码里加 print。但 Jupyter 其实给了三套调试姿势效率完全不同。第一种直接在异常之后执行%debugdef buggy(): x 1 return x / 0 buggy()报错后在下一个单元格输入%debug会自动进入事后调试模式停在出错的位置。这个时候你能做的是p x查看局部变量、u/d切换上下帧、n单步、c继续、q退出。第二种是主动在函数里加断点使用IPython.core.debugger的set_tracefrom IPython.core.debugger import set_trace def func(): a 1 set_trace() # 运行到这里会进入交互调试界面 b 2 return a b第三种是ipdb它是把 IPython 的能力和pdb结合起来的工具pip install ipdb然后在代码里import ipdb; ipdb.set_trace()在 Notebook 中的体验比纯pdb好支持 Tab 补全和彩色输出。说实话一旦习惯了用%debug事后复盘就再也不想从头加 print 再去猜了。5.3 日志、打印、变量探查三板斧调试不仅靠断点还靠对变量的快速探查。三个林林总总的函数建议背下来type(obj)看类型vars(obj)看对象属性字典dir(obj)看对象可用的属性/方法列表尤其是dir(pd.DataFrame)这样的用法比翻文档还快。配合 helphelp(df.groupby)或者df.groupby?这是 Jupyter 特有的“object? 显示文档、object?? 显示源码”的便捷查询。关于日志我长期吐槽在 notebook 里只靠print做记录效率太低。更推荐专门开一个单元配置 logging输出到文件import logging logging.basicConfig( filename./my_jupyter.log, levellogging.INFO, format%(asctime)s %(levelname)s %(message)s, ) logger logging.getLogger(__name__) logger.info(这一步跑到了参数: %s, param)这样对环境进行异常分析时至少不会因为某个输出单元格被误删而痛失线索。5.4 PermissionError 完整排查链路既然前面提到了 PermissionError这里专门放一条完整的排查链路方便直接照做先在当前环境里确认是不是只有 Jupyter 报错还是所有用户目录都写不进去。执行touch ~/.jupyter/write_test rm ~/.jupyter/write_test如果这一步也报错那就是主目录权限本身的问题检查~的属主和权限。如果写用户目录没问题再查 runtime 目录jupyter --runtime-dir ls -ld $(jupyter --runtime-dir)runtime目录下的文件要求只能是当前用户可写如果发现一些 root 属主的僵尸文件清空后重新启动。如果是在服务器上被 SELinux 或 AppArmor 限制那需要看具体的审计日志dmesg | tail -n 20里常有线索。优先考虑把 Jupyter 的数据目录放到用户自己的设定路径下绕开限制目录。最后一个兜底方案新建一个专用目录并从零配置mkdir -p ~/jupyter_data cd ~/jupyter_data jupyter notebook --notebook-dir$PWD如果这样还报错那就说明问题不在 Jupyter 本身需要去查终端里实际运行命令的用户身份是不是你想的那个人。有时候你用某云服务器的默认账号登录但 Web 界面绑定的端口启动脚本是另一个服务账号自然对某些路径没有写权限。6. 分享与复用导出、部署、插件生态里值得留意的细节6.1 导出为 md/PDF/HTML 时的边界问题在 LaTeX 和 pandoc 都安装好的环境下Jupyter 支持直接把 notebook 导出成 PDF、HTML、Markdown 等格式。命令行对应是jupyter nbconvert --to markdown my_nb.ipynb jupyter nbconvert --to html my_nb.ipynb jupyter nbconvert --to pdf my_nb.ipynb但导出看着简单坑不少。默认情况下nbconvert 会保留所有的代码输出包括那些非常长的 DataFrame 表格、动态图片、甚至报错信息。分享给别人的时候这些输出往往是噪音。解决方案是先清理输出再导出jupyter nbconvert --clear-output --to markdown my_nb.ipynb如果你想把 notebook 当作一份报告发给团队参考我经常用jupyter nbconvert --to html --template full --no-input my_nb.ipynb--no-input的意思是不渲染代码单元格只保留输出结果和 Markdown观感更像一份报表。6.2 别人给的文件怎么快速复现requirements、npm 依赖拿到别人的.ipynb最怕的就是运行到一半报ModuleNotFoundError。要让 notebook 可复现可不能只发.ipynb文件至少得带上环境说明。我在每次分享 notebook 项目时都会在同一目录下生成两份文件pip freeze requirements.txt jupyter nbextension list extensions.txtrequirements.txt记录 Python 包extensions.txt记录 Jupyter 前端插件。不要嫌它们繁琐这是能救命的“安全网”。如果有人明确都是 Lab 用户还需要注意jupyter labextension list因为前端扩展不在pip freeze范围内。在复现别人 notebook 时强烈建议开一个全新的干净环境而不是往现有的原环境里硬塞包。冲突了很难排查而且也能逼着对方把依赖说明白。常见顺序conda create -n reproduction python3.11 conda activate reproduction pip install -r requirements.txt jupyter notebook my_nb.ipynb6.3 用 Jupyter 写小系统的扩展思路最后一个环节聊聊怎么在 notebook 基础上再往前走一步。我发现不少人辛辛苦苦在 notebook 里调通了数据处理流程但每当要把它变成可复用工具时就犯难。这里有一个比较顺手的做法把 notebook 里稳定不变的逻辑抽成一个.py模块然后在 notebook 里用%autoreload调用这个模块。这样既能享受 notebook 的交互性和可视化又保住了模块化工程的可维护性。如果你想直接给非技术同事一个交互界面可以试一下 Voila 我提这个不是广告是它确实解决了从 notebook 到 Web 面板的最后一公里。它能把 notebook 里的可视化输出、交互控件包装成一个临时网页不需要你额外写 Flask 或者 Django。安装pip install voila然后启动voila my_notebook.ipynb它会自动识别代码中表征交互的 widgets 和 matplotlib 图表生成一个可点击、可滑动的浏览器应用。适合小范围内的数据看板、报表工具。还有一类场景是定时执行 notebook。虽然可以用papermill这样的工具批量跑但我的经验是当任务真的需要定时调度时Jupyter 并不是最好的载体把逻辑抽成普通脚本 cron 会可靠得多。Notebook 的优势在于“人机交互、实时反馈”真到了无人值守的生产环境脚本化和参数化才是正路。以上就是我这些年围绕 Jupyter Notebook/Lab 沉淀下来的实战要点。写到这里最想提醒你的一点是工具技巧说到底是为了少打断心流。安装选型一步到位、目录和调试两个痛点提前布置好后面每次打开 Jupyter 就能把注意力全放在问题上而不是和环境较劲。不知道你有没有遇到过更好用的小技巧如果有欢迎在评论区给我留言我也想去试试。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表