Ipythonの基本

# 概要
Pythonのデフォルトのインタプリタは色々と不満点があり調べたところ, Ipyhonの存在を知り使っていました. 今回は知らなかったIpythonの便利な機能を備忘録として残します.

# 参考資料
- [Ipython Documentation](http://ipython.readthedocs.io/en/stable/)
- Pythonによるデータ分析入門

# イントロスペクション
変数の前, もしくは後に`?`をつけると, そのオブジェクトの一般情報が見れます.
さらに`??`をつけるとその関数のソースコードを表示できます.

```text
In [1]: b = [1, 2, 3]

In [2]: b?
Type:        list
String form: [1, 2, 3]
Length:      3
Docstring:
list() -> new empty list
list(iterable) -> new list initialized from iterable's items

In [3]: ?b
Type:        list
String form: [1, 2, 3]
Length:      3
Docstring:
list() -> new empty list
list(iterable) -> new list initialized from iterable's items

In [4]: def add_numbers(a, b):
   ...:     """
   ...:     Add two numbers together
   ...:
   ...:     Returns
   ...:     -------
   ...:     the_sum : type of arguments
   ...:     """
   ...:     return a + b
   ...:

In [5]: add_numbers?
Signature: add_numbers(a, b)
Docstring:
Add two numbers together

Returns
-------
the_sum : type of arguments
File:      
Type:      function

In [6]: add_numbers??
Signature: add_numbers(a, b)
Source:
def add_numbers(a, b):
    """
    Add two numbers together

    Returns
    -------
    the_sum : type of arguments
    """
    return a + b
File:      
Type:      function
```

# シェルアクセス
`!`をつけると`!`以降の文字列はシステムのシェルで実行します.

# マジックコマンド
## %quickref
Ipythonのクイックリファレンスを表示します.

## %paste
コードのコピペができます. コードをコピーして`%paste`と打てば実行します.

## %psearch
パターンにマッチするオブジェクトを検索します. 使い方は`%psearch <オブジェクト名>*`です.

```text
In [1]: import numpy as np

In [2]: %psearch np.d*
np.datetime64
np.datetime_as_string
np.datetime_data
np.deg2rad
np.degrees
np.delete
np.deprecate
np.deprecate_with_doc
np.diag
np.diag_indices
np.diag_indices_from
np.diagflat
np.diagonal
np.diff
np.digitize
np.disp
np.divide
np.division
np.dot
np.double
np.dsplit
np.dstack
np.dtype
```

## %run
Pythonプログラムを起動できます. 使い方は`%run <ファイル名>`です.
以下のように`test.py`を起動できます.

```Py3:test.py
def f(x, y, z):
	return (x + y) / z

if __name__ == '__main__':
	print(f(4, 5, 6))
```

```text
In [1]: %run test.py
1.5
```

## %timeit
コードの実行時間を計測できます.

## %hist
入力履歴の全体あるいは一部を表示します.

## %logstart
ログ機能です. 使い方は`%logstart <ファイル名>`

# ソフトウェア開発ツール
## デバッガ
例外の発生した直後に`%debug`を入力すると, ポストモーテム・デバッガが起動されます.

```text
In [1]: run ipython_bug.py
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
/Users/-/program/python/pydata-book/ch03/ipython_bug.py in <module>()
     13     throws_an_exception()
     14
---> 15 calling_things()

/Users/-/program/python/pydata-book/ch03/ipython_bug.py in calling_things()
     11 def calling_things():
     12     works_fine()
---> 13     throws_an_exception()
     14
     15 calling_things()

/Users/-/program/python/pydata-book/ch03/ipython_bug.py in throws_an_exception()
      7     a = 5
      8     b = 6
----> 9     assert(a + b == 10)
     10
     11 def calling_things():

AssertionError:

In [2]: %debug
> /Users/-/program/python/pydata-book/ch03/ipython_bug.py(9)throws_an_exception()
      7     a = 5
      8     b = 6
----> 9     assert(a + b == 10)
     10
     11 def calling_things():

ipdb>
```

デバッガの起動後には, 任意のPythonコードの実行, その時点でのオブジェクトやデータの表示が可能です. 開始位置はエラー発生スタックの最下層になっていて, `u`および`d`でレベルを変更します.

```text
ipdb> u
> /Users/-/program/python/pydata-book/ch03/ipython_bug.py(13)calling_things()
     11 def calling_things():
     12     works_fine()
---> 13     throws_an_exception()
     14
     15 calling_things()
```

デバッガを用いることでブレークポイントを設定しての実行, 各ステージでの挙動確認のために1ステップごとの実行が可能になります. この起動にはいくつかの方法があります. 1つ目の方法は`run -d <ファイル名>`です.

```text
In [3]: run -d ipython_bug.py
Breakpoint 1 at /Users/-/program/python/pydata-book/ch03/ipython_bug.py:1
NOTE: Enter 'c' at the ipdb>  prompt to continue execution.
> /Users/kazuo/program/python/pydata-book/ch03/ipython_bug.py(1)<module>()
1---> 1 def works_fine():
      2     a = 5
      3     b = 6
      4     assert(a + b == 11)
      5

ipdb>
```

関数に入るには`s`を, ブレークポイントを設定するには`b <ブレークポイント>`, ブレークポイント手前まで処理させるには`c`, 次の行を実行するには`n`を入力します.

```text
ipdb> b 12
Breakpoint 2 at /Users/kazuo/program/python/pydata-book/ch03/ipython_bug.py:12
ipdb> c
> /Users/-/program/python/pydata-book/ch03/ipython_bug.py(12)calling_things()
     10
     11 def calling_things():
2--> 12     works_fine()
     13     throws_an_exception()
     14

ipdb> n
> /Users/-/program/python/pydata-book/ch03/ipython_bug.py(13)calling_things()
     11 def calling_things():
2    12     works_fine()
---> 13     throws_an_exception()
     14
     15 calling_things()

ipdb> s
--Call--
> /Users/-/program/python/pydata-book/ch03/ipython_bug.py(6)throws_an_exception()
      4     assert(a + b == 11)
      5
----> 6 def throws_an_exception():
      7     a = 5
      8     b = 6

ipdb> n
> /Users/-/program/python/pydata-book/ch03/ipython_bug.py(7)throws_an_exception()
      5
      6 def throws_an_exception():
----> 7     a = 5
      8     b = 6
      9     assert(a + b == 10)

ipdb> n
> /Users/-/program/python/pydata-book/ch03/ipython_bug.py(8)throws_an_exception()
      6 def throws_an_exception():
      7     a = 5
----> 8     b = 6
      9     assert(a + b == 10)
     10

ipdb> n
> /Users/-/program/python/pydata-book/ch03/ipython_bug.py(9)throws_an_exception()
      7     a = 5
      8     b = 6
----> 9     assert(a + b == 10)
     10
     11 def calling_things():
```

デバッガ名と変数名が重なった場合, 優先的にデバッガコマンドとして解釈されます. 変数として解釈させるには変数前に`!`をつけます.

```text
ipdb> !a
5
ipdb> !b
6
```

## プロファイリング
プロファイリングとはどこで時間を消費しているか確認することです. cProfileモジュールを用いることで確認することができます. 以下のコードがあったとします.

```py3:cprof_example.py
import numpy as np
from numpy.linalg import eigvals

def run_experiment(niter=100):
	K = 100
	results = []
	for _ in range(niter):
		mat = np.random.randn(K, K)
		max_eigenvalue = np.abs(eigvals(mat)).max()
		results.append(max_eigenvalue)
	return results

some_results = run_experiment()
print('Largest one we saw: %s' % np.max(some_results))
```

cProfileモジュールを経由して実行するには以下のようにします.

```bash
$ python -m cProfile <ファイル名>
```

上記のコマンドだと最も時間を消費した関数がわからないので, `-s`でソートして実行します.

```bash
$ python -m cProfile -s <ファイル名>
```

Ipythonで行うには`%prun`を使います.

```text
In [5]: %prun -l 7 -s cumulative run_experiment()
         4004 function calls in 0.401 seconds

   Ordered by: cumulative time
   List reduced from 33 to 7 due to restriction <7>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.401    0.401 {built-in method builtins.exec}
        1    0.000    0.000    0.401    0.401 <string>:1(<module>)
        1    0.001    0.001    0.401    0.401 cprof_example.py:4(run_experiment)
      100    0.365    0.004    0.371    0.004 linalg.py:832(eigvals)
      100    0.029    0.000    0.029    0.000 {method 'randn' of 'mtrand.RandomState' objects}
      100    0.002    0.000    0.003    0.000 linalg.py:214(_assertFinite)
      300    0.001    0.000    0.001    0.000 {method 'reduce' of 'numpy.ufunc' objects}
```

# Jupyter Notebook
Ipython HTML Notebookなるものが, 今は多言語に対応したJupyter Notebookとして利用可能とのことです.
Jupyter Notebookは以下の機能を持っています.
1. 40以上のプログラミング言語に対応している
2. プログラムやその実行結果をシェアできる

anacondaをインストールしていれば`jupyter notebook`で使うことができます.

# Ipythonプロファイルと構成機能
プロファイルを設定することで下記の項目の設定が可能です.

- 色設定
- 入出力プロンプト
- 任意のPythonコードの実行
- 拡張機能の有効化
- マジックコマンドやシステムエイリアスの定義

ipython_config.pyというファイルを編集したらできます.