Python
SENSYDay 5

Pythonで `light-progress` を使って進捗(プログレスバー)を表示

Pythonで進捗表示といえばtqdmが有名だと思いますが、今回はlight-progressというライブラリを紹介したいと思います。

特徴

light-progress は依存ライブラリを必要とせず軽量なライブラリを目指しており、Python2でも3でも動くようになっています。LinuxやMacではカラー表示に対応しており進行中・完了・エラー終了でそれぞれカラーが変わります。自分の環境では Jupyter Notebook でも動きました。

ただ light_progress というようにモジュール名に _ が含まれているのがイケてなかったり関数名が微妙だったりというのは気になっています。ロードマップにはコマンドラインだけでなくGUIのためのツールやWindowsでのカラー表示があります。

スクリーンショット 2018-12-04 20.08.13.png

インストール

pip install light-progress

使い方

from time import sleep
from light_progress.commandline import ProgressBar

1. 愚直な使い方

start() で進捗管理を開始し、 forward() もしくは update(i) 進捗を進めます。最後に finish() を呼び出して終了します。これは最も直接的な使い方ですがかなり不便です。

n = 42
progress_bar = ProgressBar(n)
progress_bar.start()

for item in range(n):
    sleep(0.01)
    progress_bar.forward()

progress_bar.finish()

2. 1よりちょっと手間を省く

start()finish() を自分で呼び出すのは面倒なので with 文を使って省略できます。

n = 42
with ProgressBar(n) as progress_bar:
    for item in range(n):
        sleep(0.01)
        progress_bar.forward()

3. イテレーションをライブラリに移譲

2も面倒なのでイテレーションをライブラリに移譲できます。行いたい処理は引数で渡します。

ProgressBar.iteration(range(42), lambda item: sleep(0.01))

4. ジェネレータを使う

3はコードを短くできますが、引数に関数や lambda を入れるのがあまり直感的ではありません。ジェネレータ関数を使ってイテレーション自体は移譲せずに forward() など面倒な処理だけをライブラリ側に委ねます。これが最もシンプルで使いやすい形だと思われます。

for item in ProgressBar.generation(range(42)):
    sleep(0.01)

表示のカスタマイズ

表示は widget を使ってカスタマイズすることができます。各 widget や文字列をリストにして widgets として渡すと適応できます。

from light_progress import widget
widgets = [widget.Bar(bar='=', tip='-'),
           widget.Percentage(),
           widget.Num()]

ProgressBar.iteration(
    range(42), lambda item: sleep(0.01), widgets=widgets)

# [===============-...............] 50% (21/42)
widgets = [widget.Percentage(),
           widget.Num(),
           'loading...',
           widget.Bar(bar='#', tip='>')]

ProgressBar.iteration(
    range(42), lambda item: sleep(0.01), widgets=widgets)

# 50% (21/42) loading... [###############>...............]

独自widget

progress_bar.widget.Widget を継承してクラスを作り、 get_str を実装すれば独自のwidgetが作成できます。 get_strcontext には progress_bar.core.Progress を継承したクラスのインスタンス( progress_bar.commandline.ProgressBar など)が入ってくるので、それらのプロパティを表示項目に使用できます。

表示フォーマット

widget で表示をカスタマイズできますが、format_str'{}' の入った文字列を渡すことで各widget間や配置もカスタマイズできます。なお widgets の項目数と format_str に含まれる '{}' の数は一致している必要があります。

format_str = '{} {} ({})'

widgets = [widget.Bar(), widget.Percentage(), widget.Num()]
ProgressBar.iteration(
    range(100),
    lambda item: sleep(0.01),
    widgets=widgets,
    format_str=format_str)

# [███████████████████████████████] 100% (100/100)
format_str = '{} *** {} *** ({})'

widgets = [widget.Bar(), widget.Percentage(), widget.Num()]
ProgressBar.iteration(
    range(100),
    lambda item: sleep(0.01),
    widgets=widgets,
    format_str=format_str)

# [███████████████████████████████] *** 100% *** (100/100)

くるくる回るやつ

ProgressBar だけでなく Loading くるくる回る表示もできます。

from light_progress.commandline import Loading
Loading.iteration(range(100), lambda item: sleep(0.01))

余談

ちなみにlight-progresstqdmというものがあると知らなかったときに、自分の別プロジェクトで進捗管理していた部分を独立させてPyPIに公開したものです。せっかくなので育てて行きたいと思います。