Python
Progress Bar
Coding
Programming
Software Development

Python Progress Bar

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

A progress bar is one of the simplest ways to make a long-running Python script easier to trust and easier to operate. Instead of staring at a silent terminal and guessing whether the process is alive, you can show throughput, elapsed time, and estimated completion with only a small amount of code.

The Easiest Option: tqdm

For command-line Python, tqdm is the most common default because it wraps ordinary iterables and adds progress reporting without changing the loop structure much.

Install it:

bash
pip install tqdm

Then wrap an iterable:

python
1from tqdm import tqdm
2import time
3
4for _ in tqdm(range(100), desc="Processing"):
5    time.sleep(0.02)

That gives you a progress bar, percentage, speed, and ETA in the terminal.

Why Wrapping the Iterable Works So Well

tqdm works by sitting between your code and the iterable you were already looping over. That means simple loops barely need to change.

Without a progress bar:

python
for item in items:
    process(item)

With a progress bar:

python
1from tqdm import tqdm
2
3for item in tqdm(items, desc="Items"):
4    process(item)

That low-friction API is why it shows up in data scripts, ETL jobs, notebook experiments, and one-off maintenance commands.

Progress Bars for File Processing

When reading a large file, it helps to tell tqdm the total number of iterations if you know it. That makes ETA much more accurate.

python
1from tqdm import tqdm
2
3path = "data.txt"
4
5with open(path, "r", encoding="utf-8") as f:
6    total_lines = sum(1 for _ in f)
7
8with open(path, "r", encoding="utf-8") as f:
9    for line in tqdm(f, total=total_lines, desc="Reading"):
10        _ = line.strip()

If you do not know the total ahead of time, tqdm can still show activity, but the ETA becomes less informative.

Manual Progress Updates

Sometimes you do not have a clean iterable to wrap. In those cases, create a progress bar manually and update it when work completes.

python
1from tqdm import tqdm
2import time
3
4with tqdm(total=5, desc="Steps") as bar:
5    for _ in range(5):
6        time.sleep(0.3)
7        bar.update(1)

This is useful for APIs, callback-based workflows, downloads, and concurrent task orchestration.

Progress Bars with Concurrent Work

If you are using threads or futures, update the bar as tasks finish instead of as they are submitted.

python
1from concurrent.futures import ThreadPoolExecutor, as_completed
2from tqdm import tqdm
3import time
4
5
6def work(i):
7    time.sleep(0.05)
8    return i * i
9
10jobs = range(100)
11results = []
12
13with ThreadPoolExecutor(max_workers=8) as executor:
14    futures = [executor.submit(work, i) for i in jobs]
15    for future in tqdm(as_completed(futures), total=len(futures), desc="Threads"):
16        results.append(future.result())

This reports actual completion progress, which is what operators usually care about.

Notebook-Friendly Progress Bars

In Jupyter, use the notebook renderer instead of the plain terminal version.

python
1from tqdm.notebook import tqdm
2import time
3
4for _ in tqdm(range(50), desc="Notebook run"):
5    time.sleep(0.02)

The notebook variant avoids the ugly redraw behavior you sometimes get with terminal-style output inside a notebook cell.

When You Should Disable the Bar

Progress bars are great for interactive use, but they can clutter CI logs or structured output. A good pattern is to disable them when the stream is not a terminal.

python
1import sys
2from tqdm import tqdm
3
4for _ in tqdm(range(1000), disable=not sys.stderr.isatty()):
5    pass

That keeps local runs pleasant without polluting automated logs.

Avoid Updating Too Frequently

A progress bar has overhead. In very fast loops, updating it every single iteration can cost more than the loop body itself.

Use options such as mininterval or batch your updates if necessary.

python
1from tqdm import tqdm
2
3for i in tqdm(range(1_000_000), mininterval=0.2, desc="Fast loop"):
4    _ = i * 2

For extremely cheap operations, less frequent updates are usually the right tradeoff.

Common Pitfalls

The most common mistake is wrapping a loop without giving tqdm a real total when one is easily available. The bar still works, but the ETA becomes vague and less useful.

Another issue is printing inside the loop too often. Frequent plain print calls can break the bar display and make the terminal output messy.

Developers also forget to adapt the progress bar to the environment. The terminal renderer is not always the best choice for notebooks or CI logs.

Finally, do not assume a progress bar means work is evenly distributed. A loop can show 90 percent complete while the last 10 percent takes most of the time if the later items are much heavier.

Summary

  • 'tqdm is the most practical default progress bar for Python scripts.'
  • Wrap iterables when possible and update manually when necessary.
  • Provide a total count for better ETA accuracy.
  • Use tqdm.notebook in Jupyter and consider disabling bars in CI logs.
  • Tune update frequency so the bar helps visibility without slowing the program noticeably.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.