LoginSignup
1
2

More than 1 year has passed since last update.

【Python・Jupyter】ライブラリを自動インポートする方法・マジックコマンドの作り方

Posted at

はじめに

Jupyter使いのPythonistaの皆さん、一番上のセルに毎回同じインポート文を書くことに辟易していませんか?
それと、マジックコマンド作ってますか?

今回はJupyter生活を少し快適にする、この2点について紹介してみたいと思います。

ライブラリを自動でインポートする方法

~\.ipython\profile_default\startupC:\Users\%USERNAME%\.ipython\profile_default\startup(Windowsの場合))下
のpyファイルはカーネル起動時に自動で実行されます。
本当に毎回使用するようなライブラリはこちらにインポート文を書き込んでおけば、自動的に読み込まれた状態でノートブックを開くことができます。

フォルダが見つからない場合は、コマンドラインもしくはセルから

# コマンドライン
ipython profile create

# セル
!ipython profile create

と実行すればファルダが作られると思います。

こちらにはもちろんインポート文以外も記載することが可能で、後述のマジックコマンドを定義しておけば任意のノートブックで使用可能になります。

マジックコマンドの作り方

基本的にこちらの内容です。→ Defining custom magics — IPython 7.27.0 documentation

マジックコマンドとは?

Jupyterにおけるマジックコマンドとは、%%%から始まる特殊機能の呼び出しのことを指します。
%time%%timeit%matplotlib notebookなどのコマンドは馴染み深い方も多いのではないでしょうか?

一番簡単なマジックコマンドの作り方

以下のように@register_line_magic, @register_cell_magic, @register_line_cell_magic のデコレータが付いた関数を定義することで、関数名と同名のマジックコマンドが使用可能になります。

それぞれ、
@register_line_magic%から始まる、一行のみに対するマジックコマンド。
@register_cell_magic%%から始まる、セル全体に対するマジックコマンド。
@register_line_cell_magic%から始まると%%から始まるものの両方に対応したマジックコマンド。(例:%time (%%time)
を定義することができます。

from IPython.core.magic import (register_line_magic, register_cell_magic,
                                register_line_cell_magic)

@register_line_magic
def lmagic(line):
    "my line magic"
    return line

@register_cell_magic
def cmagic(line, cell):
    "my cell magic"
    return line, cell

@register_line_cell_magic
def lcmagic(line, cell=None):
    "Magic that works both as %lcmagic and as %%lcmagic"
    if cell is None:
        print("Called as line magic")
        return line
    else:
        print("Called as cell magic")
        return line, cell 

引数のlineの部分にはマジックコマンドの横に書かれた文、
cellの部分には(マジックコマンドより下の)、セル全体の内容が渡されます。

クラスの形でのマジックコマンド定義

こちらは恐らく、マジックコマンド内、マジックコマンド間で変数を定義・管理・共有する場合に名前空間を汚さないための方法。

クラスに@magics_classデコレータをつけて、Magicsクラスを継承します。
他はデコレータの名前にregister_が付いていない以外はほとんど同じです。
クラスの外でget_ipython().register_magics(MyMagics)のような形でマジックコマンドとして登録します。

from IPython.core.magic import (Magics, magics_class, line_magic,
                                cell_magic, line_cell_magic)

# The class MUST call this class decorator at creation time
@magics_class
class MyMagics(Magics):

    @line_magic
    def lmagic(self, line):
        "my line magic"
        print("Full access to the main IPython object:", self.shell)
        print("Variables in the user namespace:", list(self.shell.user_ns.keys()))
        return line

    @cell_magic
    def cmagic(self, line, cell):
        "my cell magic"
        return line, cell

    @line_cell_magic
    def lcmagic(self, line, cell=None):
        "Magic that works both as %lcmagic and as %%lcmagic"
        if cell is None:
            print("Called as line magic")
            return line
        else:
            print("Called as cell magic")
            return line, cell

get_ipython().register_magics(MyMagics)

マジックコマンドでセルの内容を実行する方法

上記の定義で感じている方もいるかもしれませんが、マジックコマンドはほぼ「セルを関数に見立てたデコレータ」です。
それでいて、セルの内容はただの文字列として渡されてしまう不親切仕様です()。

ではどうやってセルの内容を実行するのかといいますと、get_ipython().run_cell()や、self.shell.run_cell()を使います。
これにセルの内容の文字列を渡すことで、セルを実行したときと同様に内容を実行することができます。

使用例

指定したファイルに出力を自動で書き出すセル・マジックコマンドの例です。

from IPython.core.magic import register_cell_magic

@register_cell_magic
def file_out(line, cell):
    import sys
    from io import StringIO

    tmp_stdout = StringIO()
    stdout = sys.stdout
    sys.stdout = tmp_stdout

    get_ipython().run_cell(cell)

    sys.stdout = stdout
    print(tmp_stdout.getvalue())
    with open(line, 'a') as f:
        f.write(tmp_stdout.getvalue())
%%file_out output.text
for i in range(5):
    print(i)
out
0
1
2
3
4
5

./output.txt
0
1
2
3
4
5

毎回定義せずとも任意のノートブックで使用できるようにする方法

前述のとおり、~\.ipython\profile_default\startup下のpyファイルに書き込むことで可能です。

まとめ

あわせ技

こんなマジックコマンドを用意しておけば、用途に応じたライブラリが1行で呼び出せます。

from IPython.core.magic import Magics, magics_class, line_magic

@magics_class
class MyImport(Magics):

    @line_magic
    def imports(self, line):
        if line == 'math':
            self.import_math()
        elif line == 'table':
            self.import_table()
        elif line == 'web':
            self.import_web()

    def import_math(self):
        global math, np, plt, scipy, sympy
        import math
        import scipy
        import sympy
        import numpy as np
        import matplotlib.pyplot as plt

    def import_table(self):
        global pd, np, plt, sns
        import pandas as pd
        import numpy as np
        import matplotlib.pyplot as plt
        import seaborn as sns

    def import_web(self):
        global requests, BeautifulSoup, re, urllib
        import requests
        import re
        import urllib
        from bs4 import BeautifulSoup

get_ipython().register_magics(MyImport)
usage_example
%imports table
1
2
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
2