Pythonでコンソールアプリを使う際、clickのprogressbarを使うと、長時間の作業時に進捗がいい感じに可視化されてうれしいです。
しかし、場合によってはサーバープロセスやバッチ処理に, progressbarを当初使っていた処理の関数を入れたりする場合、オプション引数でprogressbarの出力をon/offしたい、というのがあると思います。
そんなとき使えるコードパターンをご紹介します。 => file
に/dev/nullを指定するテクニックを発見したのでそちらを最初に...
UNIX系で使えるシンプルなやりかた
import sys
import click
def something(items, show_progress=False):
out = sys.stdout if show_progress else open('/dev/null', 'wb')
with click.progressbar(items, file=out) as bar:
for item in bar:
'abcd' * (1024 * 10)
items = list(xrange(10000))
something(items, show_progress=True)
print('--------')
something(items, show_progress=False)
file
というオプションでclick.progressbar
の出力先を指定できるようなので、/dev/null
へ書き込むファイルオブジェクトを指定すると、なにもでてこなくなります。
ただしこのsomething
のような関数を何千回も呼び出す場合はきちんとopenしたファイルオブジェクトをcloseした方がよいと思います。
/dev/nullがない環境でも使えるPythonのテクニックで解決するやり方
import functools
from contextlib import contextmanager
import click
@contextmanager
def dummy_bar(items, **kwargs):
yield items
def something(items, show_progress=False):
f = click.progressbar if show_progress else dummy_bar
fbar = functools.partial(f, items, show_pos=True, show_eta=True)
with fbar() as bar:
for item in bar:
'abcd' * (1024 * 10)
items = list(xrange(10000))
something(items, show_progress=True)
print('--------')
something(items, show_progress=False)
解説
なにも出力しないbarを作るものとして、dummy_bar
という関数を定義しました。
click.progressbar
はwith
句で呼び出されるため、contextmanagerを使ってas
のあとの変数に代入されるもの, すわなち引数で与えられたiterableをyield
でそのまま返しています。
使う関数をshow_progress
オプションで切り替え、統一的に引数なしで呼び出せるようにfunctools.partial
で引数を部分適用しています。
ですので本来with click.progressbar(...
となっていたところではシンプルにwith fbar()
となっています。
これでオプションの挙動に応じたbar
がas
によって代入され、あとは普通にclick.progressbar
のように使えばokです。