IPython：`autoreload 2`の動作確認


# 環境
* Python 3.6.0
* IPython 6.4.0

# 背景
pythonコードの動作確認を、IPythonで行っています。
自動的にpythonファイルをリロードするよう、以下のコマンドを設定しています。

```plain:IPython_console
In [1]: %load_ext autoreload
In [2]: %autoreload 2
```

期待した通りに自動リロードされないときがあったので、動作確認してその結果をまとめました。


## `%autoreload 2`の動き

>Reload all modules (except those excluded by %aimport) every time before executing the Python code typed.

http://ipython.readthedocs.io/en/stable/config/extensions/autoreload.html?highlight=reload 引用


# 動作確認

## pythonコード
以下のpythonファイルを使います。


```python:sample.py
# 変更前
class Sample:
    def instance_method1(self):
        print("instance_method")

def func1():
    print("func1")

```


```python:sample.py
# 変更後
class Sample:
    def instance_method1(self):
        print("instance_method1 changed")

    def instance_method2(self):
        print("instance_method2 added")

def func1():
    print("func1 changed")

def func2():
    print("func2 added")
```

## IPythonで動作確認

### ファイル変更前の状態で、コマンド実行

```
In [1]: %load_ext autoreload                                                    

In [2]: %autoreload 2                                                           
                                                                                
In [3]: from sample import *                                                    
                                                                                
In [4]: func1()                                                                 
func1                                                                           
                                                                                
In [5]: s = Sample()                                                            
                                                                                
In [6]: s.instance_method1()                                                    
instance_method1                                                                 
                                                                                
```

### ファイルを変更した後、コマンド実行

```
In [7]: func1()
func1 changed                                                                

In [8]: s.instance_method1()                                                    
instance_method1 changed                                                                

In [9]: func2()
NameError: name 'func2' is not defined

In [10]: s.instance_method2()
AttributeError: 'Sample' object has no attribute 'instance_method2'
```

メソッド内の変更は反映されましたが、メソッドの追加は反映されませんでした。


### `from sample import *`でリロード


```plain:IPython_Console
In [13]: from sample import *

In [14]: func2()
func2 added

In [15]: s.instance_method2()
AttributeError: 'Sample' object has no attribute 'instance_method2'

In [16]: s = Sample()

In [17]: s.instance_method2()
instance_method2 added

```

`import`すると、グローバルな関数の追加は反映されましたが、インスタンスメソッドの追加は反映されませんでした。
再度、`Sample`クラスのインスタンスを生成する必要がありました。


# まとめ

`autoreload 2`を設定すると、以下の動きになることが分かりました。

* メソッドの変更は反映される
* メソッドの追加は反映されない。再度`import`が必要。
* インスタンスメソッドの追加を反映させるには、`import`に加えて再度インスタンスを生成する必要がある

## `autoreload`の注意事項

自動リロードは、予期しない動きになるそうです。

>Reloading Python modules in a reliable way is in general difficult, and unexpected things may occur. 

https://ipython.readthedocs.io/en/stable/config/extensions/autoreload.html?highlight=autoreload#caveats 引用

メソッドの削除も反映されないとのこと。

>Functions that are removed (eg. via monkey-patching) from a module before it is reloaded are not upgraded.