いろいろ備忘録日記

主に .NET とか Java とか Python絡みのメモを公開しています。

Pythonメモ-71 (printデバッグの代わりに使えるライブラリ) (icecream, ic, debug, print)

概要

とても便利なライブラリ知ったので、忘れない内にメモメモ。

github.com

READMEでまず出てくるアイスクリームちゃんがかわいい!

この時点で既にいい感じです。

どんな機能?

デバッグ時によく

print(f'somevalue={somevalue}')

とかやったりしませんか? 大体どんな言語でもやるときがあると思うのですが

このようなデバッグ出力を便利に出力させてくれるライブラリです。

勿論、通常時に利用しても全然いい感じです。

インストール

現状、condaではパッケージがありませんでした。(2018/03/27時点)

なので、pipからインストール。

$ python -m pip install icecream

依存するライブラリもないので、すんなり入りました。

基本的な使い方

この記事を書いているときに使っているバージョンは

>>> import icecream
>>> print(icecream.__version__)
1.3

です。

基本的な使い方は、README.md の方に詳しく書かれているので何も困らないのですが

一応英語なので、以下自分用のメモです。

インポート

ic()のみ利用できればいいので

from icecream import ic

としておくと楽です。ちなみにic()は関数みたいに見えますが

icecream.icecream.IceCreamDebugger クラスのインスタンスです。

__call__を実装しているので、そのまま呼び出しが出来るようになっています。

値を出力

print(f'somevalue={somevalue}')

と同じようにする場合は

ic(somevalue)

で終わりです。実行すると

ic| somevalue: xxx

と表示されます。これは便利ですね。

内部でinspectモジュールを使ってフレーム情報を取得して

呼び出し部分を取得して出力してくれています。

なので、以下のように

l = list(range(10))
ic(l[-1])

とすると、ic| l[-1]: 9 って表示してくれるし

d = dict(zip(['apple', 'banana'], [100, 200])
ic(d['apple'])

とすると、ic| d['apple']: 100 と表示してくれます。

通ったかどうかの判定用

これも古いやり方かもしれませんが、やっぱりよく使われているやり方で

def tekito():
    print(0)
    # 何か処理・・・・
    print(1)
    ・
    ・
    ・

みたいに、どこを通ったのかを出力するものです。

icecream の場合は以下のように書きます。

def tekito():
    ic()
    # 何か処理・・・・
    ic()
    ・
    ・
    ・

上記のように、引数無しでic()と書いておくと

以下の用に出力されます。

ic| icecream_sample.py:73 in debug_ic()
ic| icecream_sample.py:75 in debug_ic()

ファイルと行番号と今いる関数を出力してくれます。

print(0)とかprint('step1')とかするより有意義です。

引数の値をそのまま返してくれる

ic()に渡した値をそのまま返してくれます。

なので、処理呼び出し時に渡している変数などをデバッグする際に

呼び出し前にいちいちprint入れておかなくても、以下でいけます。

def tekito(x, y):
    return x + y

x = 10
y = 20

tekito(ic(x), ic(y))

あと、先頭についている prefix を変更できたり、出力先を制御できたり(デフォルトは stderr))など

いろいろあるのですが、詳しくは 以下のちょこっと作ったサンプルや github の README などを参照ください。

サンプル

以下、ちょこっと試したサンプルです。

python icecream ライブラリのサンプル (debug, print, ic, co ...

実行すると以下のようになります。

ic| hello: 'world'
ic| l01[-1]: 9
ic| d01['apple']: 100
ic| s01.pop(): 0
ic| dat1: Data1(x=100, y=200)
0
1
2
ic| icecream_sample.py:73 in debug_ic()
ic| icecream_sample.py:75 in debug_ic()
ic| icecream_sample.py:77 in debug_ic()
ic| icecream_sample.py:88 in debug_ic2()- conn: None
ic| icecream_sample.py:91 in debug_ic2()- conn: Data1(x=100, y=200)
ic| icecream_sample.py:107 in debug_ic3()- conn: None
ic| icecream_sample.py:110 in debug_ic3()- conn: Data1(x=100, y=200)
ic| icecream_sample.py:111 in debug_ic3()
ic| x: 10
ic| y: 20
2018/03/27 14:35:45 |> icecream_sample.py:165 in go()
2018/03/27 14:35:45 |> dat1: Data1(x=100, y=200)
2018/03/27 14:35:45 |> icecream_sample.py:167 in go()

過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。

Pythonメモ-70 (SortedList, SortedDict, SortedSet) (sortedcontainers, ソート済みコレクション)

概要

pythonでソート済みコレクションを扱う際に標準ライブラリで候補に上がるのが

  • heapq モジュール使う

  • queue.PriorityQueue 使う

  • 最後に sorted かけてソートする

とかでしょうか。どれも簡単に処理かけるのですが、専用のコレクションあったほうがやっぱりなんか嬉しいです。

C#とかだと SortedListSortedDictionarySortedSet ってのがあるんですが

pythonにも似たような名前のライブラリないかなって探すと以下が見つかりました。

github.com

そのとおりのコレクションがあるみたいですね!!

pure-python で作成されてて、パフォーマンスもいいみたいです。

比較対象に、blist モジュールがいますね。

てことで、ちょこっと使ってみました。

といっても、欲しかったのが SortedList だったので、SortedDictSortedSet については調べてません。

インストール

いつもどおり、conda で入りました。

$ conda install sortedcontainers -y

SortedList

以下、メモ書き程度ですが。

"""
sortedcontainers ライブラリのサンプル

参考情報::
  http://www.grantjenks.com/docs/sortedcontainers/
"""
import bisect as bs
import contextlib as cx
import heapq as hq
import queue as que
import typing as ty
import unittest as ut
import sortedcontainers as sc


class D(ty.NamedTuple):
    id: int
    val: ty.AnyStr


class SortedListTest(ut.TestCase):
    def test_list(self):
        """リストをソート無し使用"""
        l = list()

        l.append(D(100, 'hello'))
        l.append(D(110, 'world'))
        l.append(D(10, 'hoge'))

        self.assertEqual([x.id for x in l], [100, 110, 10])

    def test_list_sorted(self):
        """リストをソートする"""
        l = list()

        l.append(D(100, 'hello'))
        l.append(D(110, 'world'))
        l.append(D(10, 'hoge'))

        sl = sorted(l, key=lambda x: x.id)

        self.assertEqual([x.id for x in sl], [10, 100, 110])

    def test_sortedlist(self):
        """SortedListを使用"""
        l = sc.SortedListWithKey(key=lambda x: x.id)

        # SortedListの場合、ソートしながら要素を追加するには
        # append() ではなく add() を使う
        # append() を使う場合は自分で挿入する順番を担保しておかないと駄目
        # つまり、これから追加する項目がソート順でも最終番目の場合 append() しても大丈夫
        # そうじゃない場合例外が発生する
        l.add(D(100, 'hello'))
        l.add(D(110, 'world'))
        l.add(D(10, 'hoge'))

        with cx.suppress(ValueError):
            l.append(D(11, 'fuga'))  # これはエラーになる

        self.assertEqual([x.id for x in l], [10, 100, 110])

    def test_heapq(self):
        """heapqを使用"""
        l = []

        d = D(100, 'hello')
        hq.heappush(l, (d.id, d))
        d = D(110, 'world')
        hq.heappush(l, (d.id, d))
        d = D(10, 'hoge')
        hq.heappush(l, (d.id, d))

        self.assertEqual([hq.heappop(l)[0]
                          for x in range(len(l))], [10, 100, 110])

    def test_bisect_insort(self):
        """bisect.insortを使用"""
        l = []

        d = D(100, 'hello')
        bs.insort(l, (d.id, d))
        d = D(110, 'world')
        bs.insort(l, (d.id, d))
        d = D(10, 'hoge')
        bs.insort(l, (d.id, d))

        self.assertEqual([x[0] for x in l], [10, 100, 110])

    def test_priorityqueue(self):
        """queue.PriorityQueueを使用"""
        q = que.PriorityQueue()

        d = D(100, 'hello')
        q.put_nowait(d)
        d = D(110, 'world')
        q.put_nowait(d)
        d = D(10, 'hoge')
        q.put_nowait(d)

        self.assertEqual([q.get_nowait()[0]
                          for x in range(q.qsize())], [10, 100, 110])


if __name__ == '__main__':
    ut.main()

参考情報

SortedContainers — sortedcontainers 1.5.9 documentation

blist: an asymptotically faster list-like type for Python — blist 1.3.6 documentation


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。

Pythonメモ-69 (標準ライブラリだけでLinuxのシステム情報を取得) (Linux System Mining with Python, Useful Blog Post)

概要

忘れないうちにメモメモ。

echorand.me

CPUやメモリやネットワークなどの情報を取得するときは

github.com

を使うことが多いと思いますが、上記のブログ記事では標準ライブラリのみを使っていろいろ取得されています。

勉強になりました。:)

記事中のスクリプトは、python2 で記述されていますので、python3で参考にする場合はちょっと変換する必要がありますね。

pythonは入っているけど、pipでインストールするようなライブラリが一切はいっていない、つまり素の状態の環境で作業することとかはよくありますので、こういうノウハウはとても大事。


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。