在VSCode中使用Jupytext实现ipynb与py文件转换
对于经常需要使用Python进行数据分析与处理的人来说,Jupyter Notebook是一个非常不错的选择。但Notebook文件在版本管理中,常常会造成麻烦。
这是因为,Notebook的.ipynb
文件格式上实质是一个Json文件,包含了相当多的辅助信息,记录了诸如单元格类型、执行次数、单元格输出等信息,且源代码实质上已经被转义成Json兼容的字符串数组。
这一特性导致,在使用Git之类版本管理工具管理Notebook源代码时,其实并不方便。举例来说,即便是切换了Notebook运行的Kernel,也会修改Notebook文件,在版本管理工具中就是一次文件改动。
显然,大多数情况下,我们希望追踪的是Notebook中的源代码,单元格输出等信息并不是使用Git等工具管理代码仓库的目标。
因此,我们是否能找到一种方法缓解上述问题呢?
用Python文件存储不就好了?
是的!非常正常的想法,既然在Notebook中我们编写的都是.py
代码,那么为什么我们不能将Notebook直接存储为.py
文件呢?
事实上,无论是Jupyter的浏览器客户端,还是nbconvert
模块,抑或是VSCode之类的编辑器,都提供了将Notebook转换为Python源代码文件的功能。
并且,只需要辅助以正确的助记符,包括Markdown单元格等信息,都可以被正常存储。
怎么转换回Jupyter Notebook?
存储的问题解决了,但怎么从.py
文件转回.ipynb
文件呢?
这时候就需要一个名为jupytext
的模块了。详情请看:https://jupytext.readthedocs.io/en/latest/。
手动转换好麻烦
不过,设想一下,如果用手动的方法,我们每次编辑一个文件将包含以下几个流程:
- 将
.py
转换成.ipynb
- 在
.ipynb
文件上编程和调试 - 一切OK后,将
.ipynb
转换为.py
- 在Git中提交更改
很麻烦对吧?有没有能帮我们自动做这些的程序呢?
当然有!jupytext
本身就提供了将.ipynb
与.py
配对的能力。
具体来说,只要将一个.ipynb
文件与指定的格式进行配对,配对完成后,当修改两个文件的其中一个,同步一下,另一个文件也将自动反映出最新更改。
这样一来,只需要在Git仓库里追踪.py
文件,然后尽情修改.ipynb
,所有更改都会自动同步。我们就实现了,在.ipynb
文件中调试,用.py
文件存储的目标。
而所谓的配对,其实也没什么特别的,无非就是在配对文件.ipynb
的metadata
里,写入配对的格式信息,例如一个最简单的HelloWorld Notebook在配对后,大概是这样的:
1 | { |
详情参见上述jupytext
文档中的示例。
VSCode里怎么办呢
然而,jupytext
的配对功能仅限于网页客户端的原生Jupyter,VSCode似乎并没有对这一功能的支持,因此似乎只能每次手动敲命令进行转换。
等一等,敲命令?那能不能让VSCode自动为我们执行转换的命令呢?别忘了VSCode的任务系统!
具体来说,我们需要做以下工作:
使用命令实现配对
由于配对是需要显示执行的,因此我们首先用命令实现这一点:
1 | jupytext --set-formats ipynb,py:percent test-hello.ipynb |
注意到上述命令中的ipynb,py:percent
了吗?它的意思是将一个.ipynb
文件与 percent 格式的.py
文件配对起来。
什么是 percent格式呢?实际上就是通过# %%
等助记符作为Notebook单元格的划分,方便阅读也方便将.py
转换回.ipynb
文件。这一格式的介绍也请阅读jupytext
的文档啦。
利用VSCode Tasks实现一键同步
现在,我们可以试着借助VSCode Tasks,实现.py
与.ipynb
文件内容更改的一键同步。
编辑工作路径.vscode/tasks.json
文件(没有就新建一个),编辑内容如下:
1 | { |
保存文件。
现在,每当我们在编辑.ipynb
或.py
文件的其中一个并保存后,只要我们按下Ctrl + Shift + B
键,运行VSCode的构建任务,我们配对的同名文件就会自动同步更改。