45026


## 経緯

Jupyter Notebook の Python 3 Kernel で
[Cython](http://cython.readthedocs.io/en/latest/src/reference/compilation.html#compiling-
notebook) を使う際、Cython 部分のソースコードを書き換えた後、 **再度実行させても変更が反映されていないことがある** と気づきました。

例えば以下の notebook を考えます。このままだと正常に動いています。

[code]

    In [1]: %reload_ext Cython
    In [2]: %%cython --name foobar            
            def f(int a, int b):
                return a + b    
    In [3]: f(5, 3)
    Out[3]: 8
    
[/code]

ここで、`return a + b` を `return a - b` に変更して再度走らせてみます。すると、本来は `2`
と出力して欲しいところ、元のまま `8` が出力されます。

[code]

    In [1]: %reload_ext Cython
    In [4]: %%cython --name foobar            
            def f(int a, int b):
                return a - b    
    In [5]: f(5, 3)
    Out[5]: 8
    
[/code]

奇妙なのでいくつか設定を変えて試してみた所、以下のことが分かりました。

  * Kernel ごと restart して最初から走らせると、更新が反映されて `2` が出力される。
  * Cython magic から `--name` / `-n` オプションを消して `%%cython` のみにすると、kernel の再起動無しに変更が反映される。
  * Cython magic に `--force` を指定しても挙動は変わらない。
  * Cython 関係なく IPython ではモジュールが再読込されないことが問題なのかと思い、["Reloading submodules in IPython"](https://stackoverflow.com/q/5364050/5989200) に従って以下の行を最初のセルに追加し再度試してみたが、挙動は変わらなかった。
[code]     %load_ext autoreload

    %autoreload 2
    
[/code]

## 質問

Cython 部分のコードを変更するたびに kernel を再起動するのは面倒です。ひとまず `--name`
の指定を外せば更新が反映されることは分かったので今はそうしていますが、 **`--name`
を付けたまま更新を逐次反映させる便利な方法は無いのでしょうか？** カーネルを再起動する以外の方法があれば、ご教示ください。

## 環境

  * Jupyter Notebook 5.4.0 + Python 3 Kernel
  * Python 3.6.4 :: Anaconda custom (64-bit)
  * Ubuntu 18.04 Bionic


CC BY-SA 4.0
2018-06-21T07:02:55.043
44947
2018-06-24T05:34:29.947
19110
question
python jupyter-notebook cython ipython
IPython + Cython でコードを変えても実行結果が変わらない


`ipython`のドキュメントの[`auto
reload`のページ](http://ipython.readthedocs.io/en/stable/config/extensions/autoreload.html)の最後にC拡張モジュールはリロードできないと書いてあります。

> C extension modules cannot be reloaded, and so cannot be autoreloaded.

C拡張モジュールがリロードできないのは、`ipython`に問題があるのではなくて、Pythonそのものに機能がないためのようです。

それで、kernelを再起動したくないのであれば、モジュール名も変更すればいいです。上の例で言えば`return a -
b`に変更するときに次のようにモジュール名を変更してやります。

[code]

    %%cython --name foobar_1            
    def f(int a, int b):
        return a - b    
    
[/code]

モジュール名を変更することは少し手間ですが、メリットもあります。

1つは、以前のモジュールに戻れるということです。以前のモジュールをインポートしてから実行すれば以前のモジュールを実行できます。

[code]

    from foobar import f
    f(a, b)
    
[/code]

また、cython
magicを走らせるとそのデータは、`~/.cache/ipython/cython`ディレクトリーのキャッシュされていきます。`--name`の指定を外した場合は、`ipython`が`_cython_magic_742f4ad2678f7a103361663cf22dd225.pyx`いうようなユニークになる名前をつけます。逆に言えばそうやってモジュール名を変えることによりリロードしなくても変更が反映されるようにしています。`--name`の指定をしておくと指定した名前`foobar.pyx`でキャッシュされます。それで、後からでもコードの中身を確認することが容易にできます。


CC BY-SA 4.0
2018-06-24T05:22:56.190
45026
2018-06-24T05:34:29.947
2018-06-24T05:34:29.947
15171
15171
44947
answer