从不同的IPython笔记本重用代码

58

我正在使用IPython,并希望从一个笔记本中运行另一个笔记本的函数(而不是在不同的笔记本之间剪切和粘贴它们)。这是否可能并且相对容易实现?

10个回答

38

使用以下命令启动您的笔记本服务器:

ipython notebook --script

将笔记本(.ipynb)另存为Python脚本(.py),您将能够导入它们。

或者查看:http://nbviewer.ipython.org/5491090/,其中包含2个笔记本,一个执行另一个。


2
如果您喜欢笔记本名称不是有效的Python模块名称(例如:包含空格和点等内容),则无法“导入”它们。但是,您可以使用%run命令。 - drevicko
2
你实际上可以从任何文件名导入,只需要多按几个键。请参阅 imp 模块。 - alexis
2
你提供的笔记本提供了回答这个问题的最佳方案:analysis.ipynb 定义了一个函数 execute_notebook,可以在另一个笔记本中运行所有代码。(不确定发生在哪个命名空间中。) - alexis
@tschm 如果你想使用Python的import命令,语法应该是import test(不需要.py)。请注意,在当前版本的IPython中,--script选项已被禁用... - drevicko
5
--script参数在3.0版本中已被移除: http://ipython.org/ipython-doc/dev/whatsnew/version3.html#backwards-incompatible-changes。替代方法是 ipython nbconvert --to python notebook (或者在该问题中提到的其他方法之一)。 - Jan Katins
显示剩余3条评论

28

15

Ipythons的%run魔法允许您在笔记本中执行Python文件和IPython脚本。我有时使用-i选项,以便在笔记本命名空间中运行它。在其中包含%run?的单元格中执行以获取更多信息。

您可以使用ipython --script在每次保存时将笔记本另存为.py文件,或在您的ipython_notebook_config.py文件中取消注释c.NotebookManager.save_script=True以达到相同的效果(使用ipython profile create进行设置 - 在Ubuntu上,配置文件位于~/.config/ipython/)。

编辑:以下内容是真实的,但是不必要的 - 您可以直接%run一个.ipynb文件。感谢Eric

如果您在要导入的笔记本中使用ipython魔术,我发现您可以将.py文件重命名为.ipy(IPython脚本),但我必须删除第一行(其中包含文件编码声明)以使其工作。可能有更好的方法!这种方法可能会混淆单元格魔法(它们都会立即应用)。


5
你可以运行 %run 'my_notebook.ipynb',这样会让你的答案更简单。 - Eric Drechsel
1
请注意,在Jupyter中--script选项已不再有效。 - Teudimundo

4

还有一个“写入和执行”扩展,它可以让您将单元格的内容写入文件(并替换旧内容 -> 更新代码),然后在另一个笔记本中导入。

https://github.com/minrk/ipython_extensions#write-and-execute

在一个笔记本中(两个单元格)

%reload_ext writeandexecute
--
%%writeandexecute -i some_unique_string functions.py
def do_something(txt):
    print(txt)

然后在另一个笔记本中:


(该内容涉及IT技术)
from functions import do_something
do_something("hello world")

3
您可以通过qtconsole连接到同一内核。只需在启动时提供此选项:
ipython qtconsole --existing kernel-0300435c-3d07-4bb6-abda-8952e663ddb7.json

在启动笔记本后查看长字符串的输出。


我该如何在控制台中获取“长字符串”?我该如何粘贴它? - Sylvain
什么操作系统?Windows、Linux还是Mac? - Mike Müller
Windows 7。我无法在窗口内选择或移动光标。 - Sylvain
使用鼠标。高亮,右键,复制。 - Mike Müller
这可能行不通。我使用了右键->标记,然后选择了区域,最后按下了回车键。不过还是谢谢。 - Sylvain
是的,如果您开启了快速编辑模式,它会像这样工作。 - Mike Müller

3

是的,你可以从一个笔记本运行另一个笔记本中的函数(而无需在不同笔记本之间剪切和粘贴它们),而且,是的,这很容易做到!

简而言之:将代码放入文件系统中的Python文件(*.py)中,并让多个笔记本使用相同的代码。(就是这么简单。)

(为什么要在笔记本中放置这么多代码,当我们有完美的代码编辑器和IDE更适合编写和阅读代码?更不用说需要适当的版本控制了!我们想要实现什么,以及代价是什么?</rant>

详细信息:

  • 将代码放入普通的Python文件中,例如my_code/foo.py,并添加(可能为空的)my_code/__init__.py
  • 利用将代码放在适当的版本控制下(例如git)--注意diff ipynb json文件的困难程度?
  • 还将笔记本放在版本控制下。裸的git日志会很难读懂,但注释可能很有用。(顺便说一句,GitHub/GitLab可以显示IPython笔记本。)
  • 将ipynb笔记本中的py源代码限制为小量的“驱动程序”代码、输出和文档。
  • 另请参见:https://ipython.org/ipython-doc/stable/config/extensions/autoreload.html
  • 如果要“内联”外部Python文件,只需使用(例如)魔法%cat my_code/foo.py...

...如果您想要更高级的内容来内联显示该源码(可选),可以将以下内容添加到外部可重用源文件中...

import IPython
from pygments import highlight
from pygments.formatters import HtmlFormatter
from pygments.lexers import get_lexer_for_filename

filename='my_code/foo.py'
with open(filename) as f: code = f.read()
formatter = HtmlFormatter(linenos='inline')
IPython.display.HTML('<style type="text/css">{}</style>{}'.format(
                formatter.get_style_defs('.highlight'),
                highlight(code, get_lexer_for_filename(filename), formatter)))

感谢您对您喜爱的代码编辑器和IDE的支持。


这并不是很实用,因为您需要重新启动IPython内核才能重新加载您正在导入的.py文件中的更改。 - sarfata
@sarfata 不是真的,参见 https://ipython.org/ipython-doc/stable/config/extensions/autoreload.html 在浏览器中编辑代码总体而言始终会比使用带有实际调试器和相关开发工具的适当 IDE 差 —— 考虑到所有警告。尽管它们很有用,但笔记本电脑是一个糟糕的替代品,也从未打算成为这样。 - michael
你可能想编辑你的回答,提到 %autoreload。谢谢。 - sarfata
完全同意你所说的,这也是我正在做的事情。自动重载起作用了。您可以调试单元格并进入Python源代码。与笔记本相比,py文件中的版本控制要好得多。 - L.T.

1
我会从其他笔记本调用笔记本。您甚至可以使用以下技巧将“参数”传递给其他笔记本:

params字典放置在“report_template.ipynb”的第一个单元格中

params = dict(platform='iOS', 
              start_date='2016-05-01', 
              retention=7)
df = get_data(params ..)
do_analysis(params ..)

在另一个(更高逻辑层次)的笔记本中,使用此函数执行它:

def run_notebook(nbfile, **kwargs):
    """
    example:
    run_notebook('report.ipynb', platform='google_play', start_date='2016-06-10')
    """

    def read_notebook(nbfile):
        if not nbfile.endswith('.ipynb'):
            nbfile += '.ipynb'

        with io.open(nbfile) as f:
            nb = nbformat.read(f, as_version=4)
        return nb

    ip = get_ipython()
    gl = ip.ns_table['user_global']
    gl['params'] = None
    arguments_in_original_state = True

    for cell in read_notebook(nbfile).cells:
        if cell.cell_type != 'code':
            continue
        ip.run_cell(cell.source)

        if arguments_in_original_state and type(gl['params']) == dict:
            gl['params'].update(kwargs)
            arguments_in_original_state = False

run_notebook("report_template.ipynb", start_date='2016-09-01')

这个命令将执行“report_template”笔记本的每个单元格,并从第二个单元格开始覆盖相关的params字典键。

1

我在笔记本中使用以下函数,以便从源笔记本加载函数或操作:

import io
import nbformat

def execute_notebook(nbfile):
    with io.open(nbfile, encoding="utf8") as f:
        nb = nbformat.read(f, as_version=4)

    ip = get_ipython()

    for cell in nb.cells:
        if cell.cell_type != 'code':
            continue
        ip.run_cell(cell.source)

使用方式如下:
execute_notebook(path/to/notebook.ipynb)

0

所以@MikeMuller的好主意对于本地笔记本电脑是可行的,但对于远程笔记本电脑就不行了(对吧?)。我认为,除非该代码执行某些相当特殊的操作来通信结果,否则您无法远程调用ipynb代码的单个单元格块或函数,并能够以编程方式将结果返回到您的调用例程中。

当@Matt提交相同的想法时,我正在撰写过程中

ipython <URI_to_Notebook> --script

*.pynb是JSON容器,而不是实际的python脚本。您可以让ipython导出*.py

如果目标*.ipynb位于您无法控制的远程计算机上,则可能需要拉取文件以便您可以将输出写入本地路径。(尚未研究是否可以在远程资源上调用此选项以创建本地输出。)创建后,您应该能够导入和运行*.py或其中的单个函数。

关于使用io.open(nbfile)批量运行另一个*.ipynb文件的那个很棒的示例,@Matt有一个问题,即nbfile是否可以是远程的?看起来像是一个很小的机会,但这将是很棒的...


是的,笔记本可以远程访问,但您需要使用类似requests的工具来获取它。它也可以存储为json格式在mongo db中...或者其他什么地方。一旦加载,它就是一个纯粹的Python字典/列表嵌套。甚至可以使用这样的工具定义一些不会在导入时执行的单元格。 - Matt

0

这里有两个额外的提示:

  1. 您还可以直接从笔记本运行%qtconsole魔法命令,它将自动连接到笔记本内核。

  2. 请查看https://github.com/atiasnir/ipnb

    您可以使用它将笔记本文件导入为标准python模块(我是作者:-))。这里的主要限制是它将丢弃魔法单元格(因为它根本不使用IPython),但其他方面应该能够正常工作。


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