IceCream使い方まとめ

## はじめに

下記記事にてIceCreamというライブラリを知り、最近使用しています。

*デバッグ時はprintではなく、Icecreamを使うと便利*
*https://qiita.com/purun/items/c7aca300b970344214cf*

IceCreamの機能についての日本語記事が見当たらないので、簡単にまとめました。

内容については基本的には[公式README](https://github.com/gruns/icecream)を参考にしていますが、
手元での実行結果とドキュメントで挙動が異なるものは実行結果を正として記載しています。
動作確認versionは2.0.0です。



## インストール

```
$ pip install icecream
```

## 基本機能
### 引数ありで実行
`ic()`に引数を渡すと、渡した引数とその値を出力してくれます。

```python
from icecream import ic

def foo(i):
    return i + 333

ic(foo(123))
```


```
ic| foo(123): 456
```

下記の場合も同様。

```python
d = {'key': {1: 'one'}}
ic(d['key'][1])

class klass():
    attr = 'yep'
ic(klass.attr)
```

```
ic| d['key'][1]: 'one'
ic| klass.attr: 'yep'
```
値を複数渡すこともできます

```python

ic(foo(123), d['key'][1], klass.attr)
```
```
ic| foo(123): 456, d['key'][1]: 'one', klass.attr: 'yep'
```

なお、[Python3.8以降であれば、f文字列で同様の出力ができる]()ようです。

```python
print(f"{foo(123)=}")
```

```
foo(123)=456
```

`ic()`を使用した場合と比べ記述が煩雑になりますが、わざわざIceCreamをインストールせずともこちらで十分な場合もあるでしょう。

### 引数なしで実行
`ic()`を引数なしで実行した場合は、実行箇所のファイル名、行数、関数名、実行時刻(UTC)を出力してくれます。
これを利用して、処理実行の有無や処理順のチェックを行うことができます。


```python
from icecream import ic

def foo():
    ic()
    first()
    
    if expression:
        ic()
        second()
    else:
        ic()
        third()
```

出力:

```
ic| main.py:4 in foo() at 12:49:18.489
ic| main.py:11 in foo() at 12:49:18.491
```

これは、下記のように`print()`に自前の引数を渡してデバッグするよりスマートです。

```python
def foo():
    print(0)
    first()

    if expression:
        print(1)
        second()
    else:
        print(2)
        third()
```
なお、`ic()`に引数を渡す場合でも、設定によってこれらのコンテキスト情報を出力することができます。[(後述)](#includeContext)
## その他
### 戻り値

`ic()` は受け取った引数をそのまま返すため、既存のコードに簡単に挿入できます。

```python
from icecream import ic
a = 6
def half(i):
    return i / 2
b = half(ic(a))
```
```
ic| a: 6
```

### 文字列を返す

コンソールへの出力を行うかわりに、`ic.format()` を使用することで文字列を返します。

```python
s = 'sup'
out = ic.format(s)
print(out)
```

```
s: 'sup'
```

#### 出力の無効化/有効化
`ic.disable()`, `ic.enable()` を呼ぶことで出力の無効化/有効化を行います。

```python
ic(1)

ic.disable()
ic(2)

ic.enable()
ic(3)
```

出力

```
ic| 1: 1
ic| 3: 3
```

`ic.disable()` することで、出力が止められます。
なお、disableで止まるのは標準エラーへの出力のみで、`ic()`,`ic.format()`からの戻り値はenable時と同様に返却されます。


## カスタム出力設定
`ic.configureOutput()`メソッドを使用して、出力値のカスタマイズができます。
### prefix
出力のprefix。デフォルトは"ic|"。

```python
ic.configureOutput(prefix='hello -> ')
ic('world')
```
```
hello -> 'world'
```

関数を渡すこともできます。

```python
def unixTimestamp():
    return '%i |> ' % int(time.time())

ic.configureOutput(prefix=unixTimestamp)
ic('world')
```
```
1519185860 |> 'world': 'world'
```

### outputFunction
文字列の出力処理にカスタム関数を渡すことができます。  
[デフォルトの関数](https://github.com/gruns/icecream/blob/v2.0.0/icecream/icecream.py#L53) では、pygmentsによるシンタックスハイライトを行ってstderrへ出力しています。
以下の例では、logging.warning()を行うカスタム関数を渡しています。

```python
def warn(s):
    logging.warning(s)

ic.configureOutput(outputFunction=warn)
ic('eep')
```
```
WARNING:root:ic| 'eep': 'eep'
```
上記の例を見るとわかりますが、`ic| 'eep': 'eep'`という生成済み文字列を受け取り、
その出力を行う関数を定義できます。


### argToStringFunction
値を文字列に変換する関数を定義できます。
デフォルトでは、値は[pprint.pformat()](https://docs.python.org/3/library/pprint.html#pprint.pformat)で整形して出力されます。

特定の型のオブジェクトに対して出力形式を定義したい場合なんかに便利そうです。

```python
import pprint
from icecream import ic

class Person:
    def __init__(self, name):
        self.name = name

p=Person(name="taro")
ic(p)

def toString(obj):
    if isinstance(obj, Person):
        return obj.name
    return pprint.pformat(obj)

ic.configureOutput(argToStringFunction=toString)
ic(p)
```
出力:

```
ic| p: <__main__.Person object at 0x10795fd60>
ic| p: taro
```

### includeContext
引数を渡して実行する時の、ファイル名・行数・親関数名を出力するオプションです。
includeContextをTrueにすることで引数を渡した際もこのコンテクスト情報を出力できます。
引数なしでの実行には影響しません。



```python
from icecream import ic

ic(0)

ic.configureOutput(includeContext=True)
ic(1)

ic.configureOutput(includeContext=False)
ic(2)
```

```
ic| arg: 0
ic| main.py:4 in foo()- arg: 1
ic| arg: 2
```

引数がない時の出力と異なり、時刻情報は出力されません。

```python
from icecream import ic

ic.configureOutput(includeContext=True)
ic()
ic(0)
```

```
ic| main.py:5 in <module> at 12:56:38.755
ic| main.py:6 in <module>- 0
```



### ※2.0.0時点で設定できないこと

- 文字列フォーマットのカスタマイズ
  - `<prefix> <context> - <arg>: <val>` という出力形式は変更できない
- 引数なし実行時の時刻出力
- 出力時刻のタイムゾーン変更

## ちなみに
Node.js, PHP, Go 等の他言語向けにも同様のライブラリがあるっぽい。
 → https://github.com/gruns/icecream#icecream-in-other-languages