Jupyter获取任意笔记本单元格内容

13
我想从Python中访问笔记本中另一个单元格的文本内容,以便将其提供给单元测试脚本,无论该单元格是否已被执行。这似乎是可能的,但我找不到在IPython内核中执行此操作的正确API。有什么想法吗? 这个问题问了同样的问题,但我不想使用魔术命令,除非我必须这样做。理想情况下,工作流程应该是“选择小部件选项”,然后是“单击小部件”以使测试运行。
背景:
我正在与一些学生一起教他们Python,在过去,当我这样做时,我设置了一堆单元测试,然后提供了如何通过shell脚本运行测试的说明。然而,我正在与一些没有家庭电脑的学生一起工作,因此我决定尝试使用Jupyter笔记本环境(通过mybinder.org)让他们做同样的事情。通过一些ipywidgets和运行任意代码集上的单元测试的辅助脚本,我已经完成了大部分工作。
3个回答

11

就已运行的单元格而言,https://ipython.readthedocs.io/en/stable/interactive/reference.html#input-caching-system所描述的输入输出缓存系统可能会很有用。(其使用示例可参见https://dev59.com/h14c5IYBdhLWcg3wapvz#27952661。)它在Jupyter笔记本中的工作原理如下所示。(相应的笔记本可以在这里查看/访问。)

enter image description here
因为在下面的评论中@A. Donda提出了关于markdown的问题,所以我在这里添加了nbformat提供的相关功能,可以与已保存的笔记本文件一起使用。使用nbformat读取已保存的笔记本文件允许获取单元格和内容,无论是代码还是markdown,并对单元格是否为markdown或代码进行排序等。我在Jupyter Discourse论坛上发布了许多使用nbformat的示例,可以通过this search here查看列表。它比相关的json.load(open('test.ipynb','r'))命令提供更多实用程序,该命令在here的注释中突出显示,以读取笔记本文件,因为自动包含了额外的笔记本上下文。

1
这仅适用于代码单元格,而不适用于文本(Markdown)单元格。 - A. Donda
1
小提示:_oh 返回单元格调用的输出(与 ____3 相同),而不是在过程中打印或显示的所有内容。可以通过 JS 调用重新获取单元格输出内容。 - Matteo Ferla
1
@A.Donda 这个问题看起来和你的相关。我在这里加了一个注释,提供了一个相关资源,如果笔记本文件已保存并且知道或可以访问该笔记本文件的名称,则可以获取 Markdown。 - Wayne

3
如果您想捕获特定单元格的内容以便从另一个单元格中访问它,一种解决方法是在执行该单元格时将其内容写入文件,然后在需要前一个单元格内容的后一个单元格中加载生成的文件(即给出前一个单元格内容的文本)。
可以通过命令“%%writefile foo.py”将单元格内容保存到文件中(在执行相应单元格时),该命令必须放置在单元格的开头。这会导致保存包含上述命令的单元格内容到文件“foo.py”,并且稍后可以再次读取它。
单元格的输出可以更轻松地使用:
只需在单元格的第一行中放置代码“%%capture output”。然后,单元格的输出(在执行后)将作为字符串保存到变量“output”中,并且可以像任何标准Python字符串变量一样使用它。
参考资料: Programmatically get current Ipython notebook cell output?https://nbviewer.jupyter.org/github/ipython/ipython/blob/1.x/examples/notebooks/Cell%20Magics.ipynb

3
我找到了一个解决方案,可以获取任何单元格的输出。它需要运行一些JavaScript。
以下是代码,您可以将其放入单元格中并运行它,它将生成一个名为 cell_outputs 的Python变量,其中包含与页面上显示顺序相同的单元格输出的数组。执行此代码的单元格的输出将为空字符串。
%%js
{
    let outputs=[...document.querySelectorAll(".cell")].map(
        cell=> {
            let output=cell.querySelector(".output_text")
            if(output) return output.innerText
            output=cell.querySelector(".rendered_html")
            if(output) return output.innerHTML
            return ""
        }
    )
    
    IPython.notebook.kernel.execute("cell_outputs="+JSON.stringify(outputs))    
}

如果您需要特定单元格的输出,请在Python代码中使用其索引,例如:cell_outputs[2] 访问第三个单元格的输出结果。
我在我的Jupyter笔记本6.0.3上测试过(通过Anaconda社区版最近安装)在Google Chrome浏览器上。上述代码在任何现代浏览器(Chrome、Firefox或Edge)上应该都可以正常运行。

我们能否在没有 %%js 单元格的情况下运行这段代码?基本上,我有一个库,其中的函数在笔记本Python单元格中被调用。我希望将上述信息放在该库函数内部。 - Djai
1
不,这个解决方案是基于Javascript的。 - BenVida

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接