转换为ipython Notebook格式

76 投票
10 回答
75649 浏览
提问于 2025-04-18 04:13

IPython Notebook自带一个叫做nbconvert的工具,可以把笔记本导出成其他格式。但是我想知道怎么把文本转换成相反的方向?我之所以问这个,是因为我已经有了一些材料和一个不错的工作流程,都是用其他格式做的,但我想利用Notebook的互动环境。

一个可能的解决办法是:可以通过导入一个.py文件来创建一个笔记本,文档中提到,当nbconvert把笔记本导出为Python脚本时,会在注释中嵌入一些指令,这些指令可以用来重新创建笔记本。不过,这种方法有一些限制,文档中没有详细说明接受的格式在哪里可以找到。(奇怪的是,样本在描述笔记本的JSON格式的部分中有提到。)有没有人能提供更多的信息,或者更好的替代方案?

编辑(2016年3月1日): 之前的答案现在不再有效,因为某种原因,这种输入格式在Notebook API的第4版中不被支持。我添加了一个自我解答,展示了如何用当前(第4版)API导入一个笔记本。(我没有撤销当前答案,因为它当时解决了我的问题,并指引我找到了我在自我解答中使用的资源。)

10 个回答

11

希望我没有来得太晚。

我刚刚在PyPI上发布了一个叫p2j的Python包。这个包可以把Python源代码文件.py转换成Jupyter笔记本文件.ipynb

pip install p2j
p2j script.py

下面是一个从.py文件生成的Jupyter笔记本的例子:

从.py文件生成的.ipynb示例

PyPI链接: https://pypi.org/project/p2j/

GitHub链接: https://github.com/remykarem/python2jupyter

11

下面是一个Python代码示例,教你如何构建IPython笔记本V4:

# -*- coding: utf-8 -*-
import os
from base64 import encodestring

from IPython.nbformat.v4.nbbase import (
    new_code_cell, new_markdown_cell, new_notebook,
    new_output, new_raw_cell
)

# some random base64-encoded *text*
png = encodestring(os.urandom(5)).decode('ascii')
jpeg = encodestring(os.urandom(6)).decode('ascii')

cells = []
cells.append(new_markdown_cell(
    source='Some NumPy Examples',
))


cells.append(new_code_cell(
    source='import numpy',
    execution_count=1,
))

cells.append(new_markdown_cell(
    source='A random array',
))

cells.append(new_raw_cell(
    source='A random array',
))

cells.append(new_markdown_cell(
    source=u'## My Heading',
))

cells.append(new_code_cell(
    source='a = numpy.random.rand(100)',
    execution_count=2,
))
cells.append(new_code_cell(
    source='a = 10\nb = 5\n',
    execution_count=3,
))
cells.append(new_code_cell(
    source='a = 10\nb = 5',
    execution_count=4,
))

cells.append(new_code_cell(
    source=u'print "ünîcødé"',
    execution_count=3,
    outputs=[new_output(
        output_type=u'execute_result',
        data={
            'text/plain': u'<array a>',
            'text/html': u'The HTML rep',
            'text/latex': u'$a$',
            'image/png': png,
            'image/jpeg': jpeg,
            'image/svg+xml': u'<svg>',
            'application/json': {
                'key': 'value'
            },
            'application/javascript': u'var i=0;'
        },
        execution_count=3
    ),new_output(
        output_type=u'display_data',
        data={
            'text/plain': u'<array a>',
            'text/html': u'The HTML rep',
            'text/latex': u'$a$',
            'image/png': png,
            'image/jpeg': jpeg,
            'image/svg+xml': u'<svg>',
            'application/json': {
                'key': 'value'
            },
            'application/javascript': u'var i=0;'
        },
    ),new_output(
        output_type=u'error',
        ename=u'NameError',
        evalue=u'NameError was here',
        traceback=[u'frame 0', u'frame 1', u'frame 2']
    ),new_output(
        output_type=u'stream',
        text='foo\rbar\r\n'
    ),new_output(
        output_type=u'stream',
        name='stderr',
        text='\rfoo\rbar\n'
    )]
))

nb0 = new_notebook(cells=cells,
    metadata={
        'language': 'python',
    }
)

import IPython.nbformat as nbf
import codecs
f = codecs.open('test.ipynb', encoding='utf-8', mode='w')
nbf.write(nb0, f, 4)
f.close()
44

这是个很老的问题,我知道。不过有一个叫做 jupytext 的工具(在 pypi 上也能找到),它可以把 ipynb 文件转换成多种格式,也可以再转换回来。

安装了 jupytext 后,你可以使用

$ jupytext --to notebook test.py

来生成 test.ipynb 文件。

jupytext 还有很多其他有趣的功能,使用笔记本时会很方便。


这里有一个关于这个话题的 更新的问题

45

由于之前的答案中的代码现在已经不再有效,我添加了这个自答,展示如何使用当前的(v4)API将内容导入到笔记本中。

输入格式

IPython Notebook API的版本2和3可以通过一些特殊的注释结构来导入Python脚本,并根据需要将其拆分成多个单元格。下面是一个示例输入文件(原始文档可以在这里找到)。文件的前两行会被忽略,而且是可选的。(实际上,读取器会忽略文件中任何地方的coding:<nbformat>行。)

# -*- coding: utf-8 -*-
# <nbformat>3.0</nbformat>

# <markdowncell>

# The simplest notebook. Markdown cells are embedded in comments, 
# so the file is a valid `python` script. 
# Be sure to **leave a space** after the comment character!

# <codecell>

print("Hello, IPython")

# <rawcell>

# Raw cell contents are not formatted as markdown

(这个API还接受一些过时的指令,比如<htmlcell><headingcell level=...>,这些会被立即转换成其他类型。)

如何导入

出于某种原因,版本4的Notebook API不支持这种格式。不过,这种格式还是很不错的,所以值得花点时间通过导入到版本3并进行升级来支持它。原则上,这只需要两行代码,加上输入输出:

from IPython.nbformat import v3, v4

with open("input-file.py") as fpin:
    text = fpin.read()

nbook = v3.reads_py(text)
nbook = v4.upgrade(nbook)  # Upgrade v3 to v4

jsonform = v4.writes(nbook) + "\n"
with open("output-file.ipynb", "w") as fpout:
    fpout.write(jsonform)

但别急!实际上,笔记本API有一个麻烦的bug:如果输入的最后一个单元格是一个markdown单元格,v3.reads_py()会把它丢掉。最简单的解决方法是在最后加一个虚假的<markdown>单元格:这个bug会把它删除,这样大家都能满意。所以在将text传递给v3.reads_py()之前,请执行以下操作:

text += """
# <markdowncell>

# If you can read this, reads_py() is no longer broken! 
"""
44

下面的内容适用于 IPython 3,但不适用于 IPython 4。

IPython 提供了一些函数,可以用来读取和写入笔记本文件。你应该使用这些函数,而不是直接创建 JSON 文件。比如,下面这段代码可以把一个脚本 test.py 转换成一个笔记本 test.ipynb

import IPython.nbformat.current as nbf
nb = nbf.read(open('test.py', 'r'), 'py')
nbf.write(nb, open('test.ipynb', 'w'), 'ipynb')

关于 nbf.read 理解的 .py 文件格式,最好直接看看 IPython.nbformat.v3.nbpy.PyReader 这个解析器类。相关代码可以在这里找到(代码不多):

https://github.com/ipython/ipython/blob/master/jupyter_nbformat/v3/nbpy.py

补充:这个回答最初是为 IPython 3 写的。我不知道在 IPython 4 中该怎么正确操作。这里是上面链接的更新版本,指向 IPython 3.2.1 版本的 nbpy.py

https://github.com/ipython/ipython/blob/rel-3.2.1/IPython/nbformat/v3/nbpy.py

基本上,你可以使用一些特殊的注释,比如 # <codecell># <markdowncell> 来分隔不同的单元格。想要完整的列表,可以查看 PyReader.to_notebook 中的 line.startswith 语句。

撰写回答