如何将一个Jupyter笔记本导入到另一个笔记本中?

4

显然可以将一个Jupyter笔记本导入到另一个笔记本中。链接页面有很多代码来实现这一点。我应该将那些代码添加到导入的笔记本中吗?页面并没有明确说明。它应该是一个通用解决方案,因此不必将所有导入其他笔记本的笔记本都添加到所有的代码。任何帮助都将不胜感激。谢谢。

2个回答

3

是的,如果您想要,可以将所有代码添加到笔记本中。

但是,作为一般解决方案,您不应该这样做。

笔记本是一个复杂的结构,在文本的详细说明中提到了这一点(我认为它是JSON)。它可以包含Python代码,也可以包含魔法命令 - cython、bash、latex等等 - 这些命令Python内核无法理解。实质上,您必须复制正常的Python导入过程的一部分功能,因为原生的Python不会理解IPython笔记本中存在Python代码的情况。

然而...通常,如果您有大量的Python代码,您会将其拆分为模块,然后导入这些模块。这些工作就像正常情况下的工作,因为它是正常的Python导入。

例如,一旦加载了告诉它如何理解笔记本的代码,实际导入只需要

import nbpackage.mynotebook

我们可以使用相同的技术来进行模块导入代码-find_notebookNotebookLoader可以放入帮助程序模块(例如helper.py),然后您只需要在笔记本中使用from helper import NotebookFinder

我猜您仍然需要在笔记本中调用sys.meta_path.append(NotebookFinder())以及导入操作。

这是一个具体的示例,演示了如何使用导入功能从笔记本中创建API:

创建一个笔记本。我们将其称为scanner.ipynb:

import os, sys
def scanner(start):
    for root, dirs,files in os.walk(start):
        # remove any already processed file
        if 'done' in dirs:
            dirs.remove('done')
        for names in files:
            name, ext = os.path.splitext(names)
            # only interested in media files
            if ext == '.mp4' or ext == '.mkv':
                print(name)

创建一个名为reuse.py的普通Python文件。 这是您通用可重复使用的IPython导入模块

#! /usr/env/bin python
# *-* coding: utf-8 *-*

import io, os, sys, types
from IPython import get_ipython
from nbformat import read
from IPython.core.interactiveshell import InteractiveShell

def find_notebook(fullname, path=None):
    """find a notebook, given its fully qualified name and an optional path

    This turns "foo.bar" into "foo/bar.ipynb"
    and tries turning "Foo_Bar" into "Foo Bar" if Foo_Bar
    does not exist.
    """
    name = fullname.rsplit('.', 1)[-1]
    if not path:
        path = ['']
    for d in path:
        nb_path = os.path.join(d, name + ".ipynb")
        if os.path.isfile(nb_path):
            return nb_path
        # let import Notebook_Name find "Notebook Name.ipynb"
        nb_path = nb_path.replace("_", " ")
        if os.path.isfile(nb_path):
            return nb_path

class NotebookLoader(object):
    """Module Loader for Jupyter Notebooks"""
    def __init__(self, path=None):
        self.shell = InteractiveShell.instance()
        self.path = path

    def load_module(self, fullname):
        """import a notebook as a module"""
        path = find_notebook(fullname, self.path)

        print ("importing Jupyter notebook from %s" % path)

        # load the notebook object
        with io.open(path, 'r', encoding='utf-8') as f:
            nb = read(f, 4)


        # create the module and add it to sys.modules
        # if name in sys.modules:
        #    return sys.modules[name]
        mod = types.ModuleType(fullname)
        mod.__file__ = path
        mod.__loader__ = self
        mod.__dict__['get_ipython'] = get_ipython
        sys.modules[fullname] = mod

        # extra work to ensure that magics that would affect the user_ns
        # actually affect the notebook module's ns
        save_user_ns = self.shell.user_ns
        self.shell.user_ns = mod.__dict__

        try:
          for cell in nb.cells:
            if cell.cell_type == 'code':
                # transform the input to executable Python
                code = self.shell.input_transformer_manager.transform_cell(cell.source)
                # run the code in themodule
                exec(code, mod.__dict__)
        finally:
            self.shell.user_ns = save_user_ns
        return mod

class NotebookFinder(object):
    """Module finder that locates Jupyter Notebooks"""
    def __init__(self):
        self.loaders = {}

    def find_module(self, fullname, path=None):
        nb_path = find_notebook(fullname, path)
        if not nb_path:
            return

        key = path
        if path:
            # lists aren't hashable
            key = os.path.sep.join(path)

        if key not in self.loaders:
            self.loaders[key] = NotebookLoader(path)
        return self.loaders[key]

创建一个特定的API文件,将上面的加载器与上面的笔记本连接起来。将其命名为 scan_api.py:

# Note the python import here
import reuse, sys

# This is the Ipython hook
sys.meta_path.append(reuse.NotebookFinder())
import scanner
# And now we can drawn upon the code
dir_to_scan = "/username/location"
scanner.scanner(dir_to_scan)

1
我并不是有很多代码,我有两个笔记本,并想将一个笔记本导入到另一个笔记本中。但是假设我想把其中一个变成一个模块,然后再导入它。那么需要做什么呢? - RussAbbott
@RussAbbott 您不需要将笔记本转化为模块 - 而是将导入代码转化为模块。嗯...如果您想要暴露特定的功能,类似于API,那么可以将笔记本转化为模块。接着,使用导入功能创建标准的“.py”文件即可。我会尝试用一个具体的例子来编辑我的答案。 - Alan

1

只需两行代码的简单解决方案

在Python中使用'nbimporter'包来导入Notebook A(或其函数)到Notebook B中。您可以使用命令'pip install nbimporter'安装'nbimporter'

假设有两个Notebook A.ipynb和B.ipynb。我们正在尝试将Notebook A(或其函数)导入B中,下面的示例代码应该解决这个问题。

在Notebook B.ipynb中

import nbimporter
import A  # or do this --> from A import func1

我的问题是我似乎无法进入我想要导入的笔记本所在的目录。我将要导入的笔记本(笔记本A)和我要导入到的笔记本(笔记本B)位于同一个Google Drive目录中。但是当我在Colab中打开笔记本B时,系统(使用!pwd命令)显示它在/content目录下,并且看不到笔记本A,它只能看到sample_data目录。我该如何进入正确的目录? - RussAbbott
即使我提供了完整路径,也无法直接使用!cd进入正确的目录:! cd“C:\Users\rabbott\Google Drive\Colab Notebooks” - RussAbbott
尝试了整整两分钟的nbimporter,它似乎是一款相当愚蠢的软件,因为它试图解析笔记本中的Markdown部分:```---> 14 "\n", 15 "## Actions:\n", 16 " \n",NameError: name 'actions' is not defined``` 它显然确实导入了笔记本(目录没有问题),因为它可以看到我正在调用的函数,但随后它就彻底失败了。 - Marco Massenzio

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