IPythonにモジュールを自動リロードしてほしいとき
- IPython上でモジュールを
import
する。 - コードスニペットを書いてテストしてみる。
- エディタでモジュールを書き直す。
- 反映させるにはIPythonごと再起動する必要がある。
- 「なんで?」ってなる。
では、自動化を始めましょう。
とってもキュートなIPython
IPython、便利ですよね。
- コードの自動補完もあるし
- 自作クラスでも推測してくれるし
- シンタックスハイライトもあるし
- インデントもよしなに管理してくれるし
Ctrl-↑
とかで定義ごとさかのぼったりできるし%save
で保存できるし
Wikipediaの記事によればクラスタ環境で並列コンピューティングも可能だとかで、ちょっと 'An enhanced Interactive Python' どころの騒ぎじゃない気もします。個人的には、貧弱なWindows環境でも拡張可能なシェルとして使えるのが嬉しいな、くらいです。
大抵のことを透過的にやってくれるあまり、「あっやばいEmacsのつもりでキー叩いちゃった」と思ったら「あれっ期待通りに動いてて良きかな?」みたいなことも結構あります。ed
やsed
などストリームエディタのヘビーユーザーなら、そのままエディタとして使えるんじゃないでしょうか。素敵ですね。
しかしなぜでしょう。モジュールのリロードだけが(標準では)できません。いくらimport
をしようが、一度読み込まれた定義が上書きされたり更新されることはないのです。モジュール間でimport
が呼び出されまくってる場合に備えたメモライズ処理なのかもしれませんし、一種のPythonic Wayなのかもしれません。
[1]: import hack_challenge [2]: hack_challenge.greet() May the source be with you! # -- greet関数を書き換える -- [3]: import hack_challenge [4]: hack_challenge.greet() May the source be with you! # ←変わってない [5]: quit $ ipython [1]: import hack_challenge [2]: hack_challenge.greet() Modules are red / DocStrings are blue / SyntaxSugar is sweet / And IPython here. # ←やっと反映される
複雑なモジュールを扱うならわかります。でも私は「ちょっとしたREPL」として使いたいので、せめて%reload
とかそういうコマンドがほしいのです。
ならば%autoreload
を使うが良い
かつて古いバージョンには%reload
というまんまなコマンドがあったらしいのですが、2008年当時の話なのでだいぶ昔です。しかしその代わり、今はautoreload
という拡張コマンドが用意されています。
[1]: %load_ext autoreload [2]: %autoreload 2
こう宣言しておくとimport
したファイルが変更されるたびに自動的に読み込まれるので、 ログだけ見るととんでもない副作用が発生する関数のように見えます。 実際はただ合間にソースコードを変更しただけなんですけど。
%autoreload 2
の2
ってなんだよという方は公式ドキュメントをスポイルするか、Qiitaの記事(ipython を起動しながら自作モジュールを修正した場合)を参考にしてください。
%load_ext
も自動化したい
%load_ext autoreload
, %autoreload 2
という2行を入力することさえ手間だと感じる人、または構文やコマンドごと忘れた未来の自分のためにメモを残しておきます。
IPythonはシェルとして使用できると先ほど書きましたが、この機能を支えるのは『プロファイル』と呼ばれる設定ファイル群であり、細かく挙動を管理したり、複雑な設定を一発で切り替えることができます。bash
で言えば.bash_profile
のようなものですが、名前で管理したり、参照先のディレクトリを指定したりと、高い柔軟性を備えています。
私は今のところそこまで使い込む予定はないので、素直にデフォルトのプロファイルを作って設定ファイルを初期化します。
$ ipython profile create
$ ls ~/.ipython/profile_default/
db/ history.sqlite ipython_config.py log/ pid/ security/ startup/
これを行わないとipython_config.py
が生成されません。一から書いてもいいのですが、コマンドで生成される設定ファイルはコメントで雛形になっているのでおすすめです。
ipython_config.py
を開いて編集します。変更するのは32行目付近にあるc.InteractiveShellApp.exec_lines
とc.InteractiveShellApp.extensions
の2つです。
# lines of code to run at IPython startup. c.InteractiveShellApp.exec_lines = [ '%autoreload 2', 'print("Notice: disabling autoreload in ipython_config.py will improve performance.")', ] # A list of dotted module names of IPython extensions to load. c.InteractiveShellApp.extensions = [ 'autoreload' ]
前者は起動時に実行するPythonコードのリスト、後者は自動的に読み込む拡張のリストです。
print
は無くても構いませんが、どうも調べた結果autoreload
はかなりIPythonに負荷をかけるようなので、設定したことを忘れて「IPythonが重い!」などと言い出しかねない自分に向けてメッセージを残しておきます。
では、快適なPythonライフを。