LoginSignup
1
1

More than 3 years have passed since last update.

Jupyter(IPython)でNoteBookをモジュールとしてインポートする方法

Posted at

Jupyter notebook で別のnotebookの関数を使う方法は公式サイトやQiita でも紹介されていますが、それをちょっとだけ便利にする方法を紹介します。

基本的には公式サイトの通りです。
https://jupyter-notebook.readthedocs.io/en/latest/examples/Notebook/Importing%20Notebooks.html

Qiitaにも良い紹介記事があります。
https://qiita.com/tdual/items/32d3918b4c8dd1f703e7

ただ、使いにくいのは import 時に notebook の内容がすべて実行されてしまうことです。全部のセルではなく一部のセルに定義した変数や関数だけ他の notebook でも使いたい! fastai の nbdev では、そのような場合はセルの先頭に"#export" という印をつけます。でも、nbdev のように大げさにしたくない。

なので、公式サイトにあるプログラムの NotebookLoader クラスに修正を加え、先頭に"#export" と印をつけたセルだけインポートされるように修正します。

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):
    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
        nb_path = nb_path.replace("_", " ")
        if os.path.isfile(nb_path):
            return nb_path

class NotebookLoader(object):
    def __init__(self, path=None):
        self.shell = InteractiveShell.instance()
        self.path = path

    def load_module(self, fullname):
        path = find_notebook(fullname, self.path)
        with io.open(path, 'r', encoding='utf-8') as f:
            nb = read(f, 4)
        mod = types.ModuleType(fullname)
        mod.__file__ = path
        mod.__loader__ = self
        mod.__dict__['get_ipython'] = get_ipython
        sys.modules[fullname] = mod
        save_user_ns = self.shell.user_ns
        self.shell.user_ns = mod.__dict__
        try:
          for cell in nb.cells:
            if cell.cell_type == 'code':
                code = self.shell.input_transformer_manager.transform_cell(cell.source)
                # セルの先頭に "#export" と記述されているセルだけ実行する 
                if code.startswith("#export"):
                    exec(code, mod.__dict__)
        except Exception as ex:
            # セルに"#export" を付け忘れる場合が多いので、どこでエラーになったかわかるようにする
            print(code)
            raise ex
        finally:
            self.shell.user_ns = save_user_ns
        return mod

class NotebookFinder(object):
    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]

これを nb_finder.py などのファイル名で保存します。使うときは

import sys
import nb_finder as nbf
sys.meta_path.append(nbf.NotebookFinder())

とすれば、以降は他の notebookをimportすることができます。

from mynotebook import *

インポート元の notebook では、他の notebook でも使いたい変数や関数を記述しているセルの先頭に "#export" を追加してください。そのセルを実行するのに必要な import文のあるセルにも #export を付けることを忘れないでください。
また、#export ではなく、不要なセルに #hide と指定するとそのセルはインポートされないようにするようにしても良いかもしれません。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1