はじめに
Jupyter使いのPythonistaの皆さん、一番上のセルに毎回同じインポート文を書くことに辟易していませんか?
それと、マジックコマンド作ってますか?
今回はJupyter生活を少し快適にする、この2点について紹介してみたいと思います。
ライブラリを自動でインポートする方法
~\.ipython\profile_default\startup
(C:\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)
0
1
2
3
4
5
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)
%imports table