閉じる

【Python】tqdmの使い方入門|最速で進捗バーを実装する方法

Pythonで時間のかかる処理を書くとき、今どれくらい進んでいるのかが分かると安心できます。

そうした場面で便利なのが、わずか数行のコードで進捗バーを表示できるライブラリ「tqdm」です。

本記事では、Python初心者の方でもすぐに使い始められるように、tqdmのインストールから基本的な使い方、実務で役立つ応用テクニック、カスタマイズ方法やトラブル対処までを、図解を交えながら丁寧に解説していきます。

tqdmとは|Pythonで簡単に進捗バーを表示する方法

tqdmの概要と特徴

tqdmは、Pythonのループ処理に簡単に進捗バーを追加できるライブラリです。

名前はアラビア語の「taqaddum(進捗)」と、英語の「progress」に由来しており、その名の通り「どれくらい処理が進んでいるか」を視覚的に表示してくれます。

tqdmの最大の特徴は、既存のコードをほとんど変えずに導入できる点です。

通常のforループに対して、イテラブル(リストやrangeなど)をtqdm()で包むだけで、ターミナルやJupyter Notebook上に進捗バーを出すことができます。

例えば、次のような処理があったとします。

Python
for i in range(100):
    do_something(i)

このrange(100)の部分をtqdm(range(100))に変えるだけで、進捗バーつきのループに早変わりします。

Python
from tqdm import tqdm

for i in tqdm(range(100)):
    do_something(i)

処理が終わるまでの残り時間や、1秒あたりに処理している速度(イテレーション数/秒)も自動で表示されるため、長時間かかるバッチ処理の目安をつかむのにも役立ちます。

tqdmがPythonで人気の理由

tqdmがPythonコミュニティで広く使われている理由はいくつかあります。

まず、導入が非常に簡単で、既存コードの修正量が最小限で済むことが挙げられます。

先ほど触れたように、イテラブルをtqdm()で包むだけなので、大規模なリファクタリングは不要です。

次に、動作が軽くオーバーヘッドが小さいことも重要です。

ループ自体が非常に高速な場合を除けば、tqdmを挟んでも処理全体の速度にほとんど影響しません。

内部で賢く更新間隔を調整し、必要以上に画面書き換えを行わないように設計されています。

また、tqdmは以下のような環境で安定して動作します。

  • 通常のターミナル(コンソール)
  • Jupyter Notebook / JupyterLab
  • Google Colab
  • Windows / macOS / Linux など主要OS

さらに、pandasやマルチプロセス処理、ファイル処理などとの連携機能が豊富で、開発環境から本番バッチ、データ分析まで幅広い場面で活用されているのも人気の理由です。

tqdmをインストールする

tqdmはPyPIで配布されているため、pipを使って簡単にインストールできます。

以下のコマンドをターミナル(もしくはコマンドプロンプト)で実行します。

Shell
pip install tqdm

Pythonのバージョンを複数インストールしている環境や、Python 3系用のpipがpip3になっている場合は、次のように実行します。

Shell
pip3 install tqdm

仮想環境(venvやconda)を使っている場合は、仮想環境を有効化した状態で上記のコマンドを実行してください。

インストールが完了したか確認するには、Pythonの対話モードでインポートしてみると確実です。

Python
>>> from tqdm import tqdm
>>> tqdm
<class 'tqdm.std.tqdm'>

このようにエラーなくクラスが表示されれば、問題なくインストールされています。

tqdmの基本的な使い方

rangeとfor文でtqdmを使う基本構文

tqdmの最も基本的な使い方は、forループのイテラブルをtqdm()で包むことです。

構文としては非常にシンプルです。

Python
from tqdm import tqdm

for 要素 in tqdm(イテラブル):
    処理

たとえば、0から99までの100回ループを回す場合は次のようになります。

Python
from time import sleep
from tqdm import tqdm

for i in tqdm(range(100)):
    # ここに時間のかかる処理を書くイメージ
    sleep(0.05)

このコードをターミナルで実行すると、以下のような進捗バーが表示されます(あくまでイメージです)。

 34%|███████████████▎                    | 34/100 [00:01<00:02, 25.76it/s]

ここで34%が進捗率、34/100が現在のループ回数と総回数、it/sが1秒あたりのイテレーション数を示しています。

tqdmの最小コード例

tqdmを試してみるための、最小限のサンプルコードを示します。

複雑な処理は書かずに、単にループを回すだけの例です。

Python
from time import sleep
from tqdm import tqdm

for _ in tqdm(range(50)):  # 0〜49までの50回ループ
    sleep(0.1)             # 0.1秒待つだけのダミー処理

このサンプルを実行すると、コンソールには次のような出力が流れていきます(表示は環境によって多少異なります)。

  0%|          | 0/50 [00:00<?, ?it/s]
 10%|█         | 5/50 [00:00<00:04, 10.52it/s]
 50%|█████     | 25/50 [00:02<00:02, 10.26it/s]
100%|██████████| 50/50 [00:04<00:00, 10.10it/s]

わずか3行の追加で「どこまで終わっているか」「あと何秒ぐらいかかりそうか」が一目で分かるため、試す価値は十分にあります。

tqdmの表示を日本語環境で使う際の注意点

日本語環境でtqdmを使う場合、文字コードや端末の設定によっては進捗バーや日本語テキストが崩れることがあります。

特にWindows環境では、デフォルトのコードページがUTF-8ではないことがあるため注意が必要です。

一般的な対処としては、次のポイントを意識します。

  • 端末(ターミナル)の文字コードをUTF-8に設定する
  • Pythonスクリプト自体のエンコーディングをUTF-8にする(先頭に# -- coding: utf-8 --をつけるか、ファイル保存時の文字コードをUTF-8にする)
  • tqdmのdescに日本語を指定する際は、環境によっては文字化けする可能性があることを認識しておく

実際に日本語の説明テキストをつけた例は後述しますが、もし日本語を付けた途端にバーが崩れる場合は、まず端末の文字コード設定を疑うとよいです。

実務で使えるtqdmの応用テクニック

リストやイテレータに対してtqdmを使う

tqdmはrange()だけでなく、任意のイテラブル(繰り返し可能オブジェクト)に対して使うことができます。

たとえば、リストやタプル、ジェネレータ、ファイルオブジェクトなども対象になります。

リストに対してtqdmを使う例

Python
from time import sleep
from tqdm import tqdm

items = ["apple", "banana", "orange", "grape"]

for fruit in tqdm(items):
    # フルーツ名を処理するダミー
    sleep(0.5)

ファイル行ごとにtqdmを使う例

Python
from time import sleep
from tqdm import tqdm

# サンプル用に仮のファイルパス
file_path = "large_text_file.txt"

with open(file_path, "r", encoding="utf-8") as f:
    for line in tqdm(f):
        # 各行を処理する(ここではダミーでスリープ)
        sleep(0.01)

ジェネレータに対して使う例

Python
from time import sleep
from tqdm import tqdm

def generate_numbers(n):
    for i in range(n):
        yield i

for num in tqdm(generate_numbers(100)):
    sleep(0.02)

このように、「forで回せるもの」は基本的になんでもtqdmの対象にできると考えてよいです。

enumerateとtqdmを組み合わせる方法

ループ処理でenumerate()を使い、indexと値を同時に取得したい場面はよくあります。

tqdmと組み合わせる際は、tqdmの外側にenumerateを置くか、内側に置くかで悩むことがありますが、基本的には次のように書くのが自然です。

Python
from time import sleep
from tqdm import tqdm

items = ["a", "b", "c", "d"]

for i, item in enumerate(tqdm(items)):
    sleep(0.3)
    # iがインデックス、itemが要素

この書き方だと、tqdm(items)がイテラブルとなり、それをenumerate()で包んでいる形です。

逆に、次のように書くこともできます。

Python
for i, item in tqdm(enumerate(items), total=len(items)):
    sleep(0.3)

この場合、tqdmに渡しているのはenumerate(items)になり、かつtotal=len(items)で全件数を指定しています。

どちらの書き方でも動作しますが、特に理由がない限りは前者の「tqdm(items)をenumerateで回す」方が読みやすいです。

tqdmで進捗バーに説明テキスト(desc)を付ける

tqdmでは、進捗バーの左側に任意の説明テキストを表示できます。

このテキストはdesc引数で指定します。

Python
from time import sleep
from tqdm import tqdm

for i in tqdm(range(100), desc="データ処理中"):
    sleep(0.05)

出力イメージは次のようになります。

データ処理中:  35%|███████████████▋                | 35/100 [00:02<00:03, 18.24it/s]

日本語のdescを使うときは、前述の通り端末の文字コードに注意が必要です。

もしうまく表示されない場合は、一旦英語だけで試し、問題がなければ端末側の設定を疑うとよいです。

処理件数(total)を指定して正確な進捗率を表示する

tqdmは、イテラブルがlen()に対応している場合には自動で総件数を推定します。

しかし、ジェネレータやデータベースカーソルなど、長さが事前に分からないイテラブルだと、総件数が表示されず「??it」となることがあります。

そうした場合には、total引数で総件数を明示的に指定することで、正確な進捗率や残り時間を計算させることができます。

Python
from time import sleep
from tqdm import tqdm

# 実際にはDBの件数などを事前にカウントしておくイメージ
total_records = 200

def record_generator(n):
    for i in range(n):
        yield i

for record in tqdm(record_generator(total_records), total=total_records, desc="レコード処理"):
    sleep(0.02)

totalを指定すると、完了までの見積もり時間(ETA)が精度良く表示されるため、バッチ処理などではできるだけ指定するのがおすすめです。

ネストしたループでtqdmを使う

複数のループが入れ子(ネスト)になっている処理でも、tqdmを使うことでそれぞれのループに対して進捗を表示できます。

ただし、そのまま2つのtqdmを使うと、コンソールの表示が少し見づらくなる場合があります。

基本的なパターンは次のような書き方です。

Python
from time import sleep
from tqdm import tqdm

outer_list = range(3)
inner_list = range(5)

for i in tqdm(outer_list, desc="外側ループ"):
    # 外側ループの処理(重い処理を想定)
    sleep(0.5)
    for j in tqdm(inner_list, desc="内側ループ", leave=False):
        # leave=False で内側バーを消していく
        sleep(0.2)

ここでleave=Falseを指定すると、内側ループのバーは完了後に消え、外側のバーだけが残るため、ログが縦に長くなりすぎるのを防げます。

ネストが深くなるほど進捗の解釈が難しくなります。

実務では「外側ループだけtqdmを付ける」「本当に重要なレベルだけ進捗バーを出す」という割り切りもよく行われます。

pandasのapplyとtqdmを連携させる

データ分析でよく使われるpandasのapply()メソッドとも、tqdmは簡単に連携できます。

pandas専用のフック機能が用意されているため、progress_apply()というメソッドで進捗バーつきのapplyを実行できます。

まず、pandasとtqdmをインポートし、tqdmのpandas拡張を有効にします。

Python
import pandas as pd
from tqdm import tqdm

# tqdmのpandas拡張を有効化
tqdm.pandas()

その上で、通常のapply()ではなくprogress_apply()を呼び出します。

Python
import pandas as pd
from tqdm import tqdm
from time import sleep

tqdm.pandas()  # これを一度呼ぶ

def heavy_function(x):
    sleep(0.01)  # ダミーの重い処理
    return x * 2

df = pd.DataFrame({"value": range(100)})

# progress_applyで進捗バー表示
df["result"] = df["value"].progress_apply(heavy_function)

Jupyter環境では、自動的にNotebook用のバーが使われるか、もしくは後述のtqdm.notebookを使うことで、見やすいGUI風の進捗バーを表示できます。

関数内・クラス内でtqdmを使うベストプラクティス

大規模なプロジェクトやライブラリ開発では、関数やクラスの内部でtqdmをどう扱うかが設計のポイントになります。

乱暴に書くと、内部でベタにtqdm()を呼んでしまい、テストや他の環境で不要なバーが出てしまうことがあります。

おすすめのパターンは以下の2つです。

1. 呼び出し側からdisableフラグを渡す

Python
from time import sleep
from tqdm import tqdm

def process_items(items, show_progress=True):
    iterator = items
    if show_progress:
        iterator = tqdm(iterator, desc="items処理")
    for item in iterator:
        sleep(0.1)

if __name__ == "__main__":
    data = range(50)
    process_items(data, show_progress=True)   # バーあり
    # process_items(data, show_progress=False) # バーなし

このように進捗を出すかどうかを引数で切り替えられるようにしておくと、テスト時などにバーを抑制できて便利です。

2. tqdmインスタンスを外から渡す

もう少し柔軟にしたい場合は、tqdm風のオブジェクトを引数で受け取り、外部から差し込めるようにします。

Python
from time import sleep
from tqdm import tqdm

def process_items(items, progress_wrapper=None):
    if progress_wrapper is None:
        # そのままのイテラブルを返す関数を使う
        progress_wrapper = lambda x: x

    for item in progress_wrapper(items):
        sleep(0.1)

if __name__ == "__main__":
    data = range(30)

    # 進捗バーあり
    process_items(data, progress_wrapper=lambda x: tqdm(x, desc="処理中"))

    # 進捗バーなし
    process_items(data)

このように設計しておけば、ライブラリ側のコードを変更せずに、呼び出し側でtqdmの有無や種類(コンソール用・Notebook用など)を切り替えることができます。

tqdmのカスタマイズとトラブル対処

tqdmの表示フォーマットと幅をカスタマイズする

tqdmはデフォルトのままでも十分便利ですが、表示の幅やフォーマットをカスタマイズすることで、ログと共存しやすくしたり、限られた横幅の中に必要な情報だけを表示するといった調整ができます。

代表的なカスタマイズパラメータは次の通りです。

  • ncols: 進捗バー全体の幅(カラム数)
  • bar_format: 進捗バーの構成を細かく指定する文字列
  • unit: 単位表示(デフォルトはit)
  • unit_scale: 件数に応じてK, Mなどをつけるかどうか

幅を固定する例(ncols)

Python
from time import sleep
from tqdm import tqdm

for i in tqdm(range(100), ncols=60, desc="幅60のバー"):
    sleep(0.05)

フォーマットを変える例(bar_format)

Python
from time import sleep
from tqdm import tqdm

bar_format = "{l_bar}{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}]"

for i in tqdm(range(50), bar_format=bar_format, desc="シンプルバー"):
    sleep(0.1)

bar_formatでは、使えるプレースホルダが多数用意されており、必要な情報だけを表示することが可能です。

たとえば{percentage:3.0f}%でパーセンテージのみ、{rate_fmt}で速度、{remaining}で残り時間などを指定できます。

公式ドキュメントには詳細なプレースホルダ一覧が載っているので、本番環境のログに合わせてチューニングしたい場合は参照するとよいです。

ログ出力とtqdmの表示が混ざる問題の対処法

tqdmを使っていると、print文やloggingの出力が進捗バーの途中に割り込んで、画面が乱雑になることがあります。

これは、tqdmが同じ行を上書きしてバーを更新しているのに対して、通常の出力が改行を伴っていきなり表示されるために起こります。

この問題に対処するには、次のような方法があります。

1. tqdm.write()を使う

tqdmは、進捗バーと干渉しないようにログを出力するためのtqdm.write()を提供しています。

printの代わりにこれを使うと、バーを壊さずにメッセージを書き込めます。

Python
from time import sleep
from tqdm import tqdm

for i in tqdm(range(10), desc="処理中"):
    sleep(0.3)
    if i == 5:
        tqdm.write("途中経過: i=5 です")  # バーときれいに共存

2. loggingハンドラと連携させる

より本格的には、loggingモジュールと連携させる方法もあります。

tqdmにはtqdm.contrib.loggingモジュールがあり、ログ出力をtqdmに合わせて調整してくれるハンドラを提供しています。

ここでは詳細なコードは割愛しますが、本番バッチで大量のログと進捗バーを両立させたい場合には検討に値します

Jupyter Notebookでtqdm.notebookを使う

Jupyter NotebookやJupyterLab、Google Colabなどのノートブック環境では、コンソール用のtqdmではなく、専用のtqdm.notebookを使うと、より見やすいプログレスバーが表示されます。

基本的な使い方は次の通りです。

Python
from time import sleep
from tqdm.notebook import tqdm

for i in tqdm(range(100), desc="Notebookバー"):
    sleep(0.05)

この場合、ブラウザ上にカラフルなバーが表示され、セルの下に静的に表示され続けるため、ノートブックをスクロールしても進捗を追いやすくなります。

pandasとの連携でも、Notebook環境ならtqdm.notebookと組み合わせることで、DataFrame処理の進捗をGUIライクに管理できます。

tqdmが表示されない・崩れる場合のチェックポイント

tqdmを使っていて、「進捗バーがまったく表示されない」「バーがぐちゃぐちゃに崩れる」といった問題に遭遇することがあります。

そんなときは、次のポイントを順に確認すると原因を絞り込みやすくなります。

1. 実行環境の種類を確認する

  • 通常のターミナル上で動かしているか
  • Jupyter Notebook / JupyterLab / Colabなどブラウザ環境か
  • IDEのビルトインターミナル(PyCharmなど)か

ノートブック環境ではtqdm.notebookを使う方が安定しますし、一部のIDE内ターミナルでは制御文字の扱いが特殊なことがあります。

2. 出力先がリダイレクトされていないか

ファイルに標準出力をリダイレクトしている場合や、サーバープロセスのログに書き込んでいる場合など、tqdmのような「行を上書きしながら進捗表示する」仕組みがうまく機能しないことがあります。

その場合はdisable=Trueでバーを無効化したり、minintervalを大きくするといった調整が必要です。

Python
from tqdm import tqdm

for i in tqdm(range(100), disable=False, mininterval=1.0):
    ...

3. 日本語や特殊文字の有無

前述の通り、日本語や絵文字などの全角文字をdescに含めると、端末によってはバーの幅計算が崩れます。

いったん英数字だけにしてみて、問題が解消するかを確認すると切り分けに役立ちます。

4. マルチプロセス・マルチスレッドとの併用

multiprocessingやマルチスレッド環境で複数のtqdmインスタンスが同時に出力すると、互いの出力が競合してバーが崩れることがあります。

この場合、position引数を使ってバーの行位置を固定したり、ログを一元管理するプロセスを用意するなどの設計が必要になります。

5. tqdmのバージョン

環境によっては、古いバージョンのtqdmで不具合が残っている場合があります。

一度最新版にアップデートしてから再現するかどうかを試すとよいです。

Shell
pip install -U tqdm

まとめ

tqdmは、Pythonで時間のかかる処理を書くときに、ほんの1行追加するだけで進捗バーを表示できる強力かつ軽量なライブラリです。

本記事では、基本的なfor tqdm(range(...))の使い方から、リストやジェネレータ、enumerateやpandasとの連携、descやtotalによる情報付加、ネストループや関数・クラス内での設計までを一通り解説しました。

また、bar_formatやncolsによるカスタマイズ、ログとの干渉を避けるtqdm.writeの活用、Jupyter専用のtqdm.notebook、表示崩れの対処ポイントなど、実務で遭遇しがちな問題にも触れました。

まずは小さなループからtqdmを導入し、自分の開発や分析フローに自然に溶け込ませていくことで、日々の作業の見通しと安心感を大きく高めることができます。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!