Build a Progress Callback Function for Loops in Python

Create a reusable progress callback that receives per-step data and lets callers log or update a UI as a loop runs.

Easy Python 3.9+ Aug 9, 2026 Functions & basics 14 views 0 copies

Python code

34 lines
Python 3.9+
def run_with_progress(items, desc="Processing", step_callback=None):
    """Run a loop with progress updates via callback."""
    total = len(items)
    for idx, item in enumerate(items):
        # Process the item (simulated work here)
        result = item * 2

        # Build progress data dictionary
        if step_callback:
            progress_data = {
                "index": idx + 1,
                "total": total,
                "percent": round((idx + 1) / total * 100, 1),
                "item": item,
                "result": result,
            }
            step_callback(progress_data)

    return total


def print_progress(data):
    """Example step callback that logs progress to console."""
    suffix = f"({data['index']}/{data['total']})"
    print(
        f"{data['percent']}% {suffix}: "
        f"item={data['item']} -> result={data['result']}"
    )


if __name__ == "__main__":
    items = [10, 20, 30, 40, 50]
    completed = run_with_progress(items, step_callback=print_progress)
    print(f"\nCompleted {completed} items.")

Output

stdout
20.0% (1/5): item=10 -> result=20
40.0% (2/5): item=20 -> result=40
60.0% (3/5): item=30 -> result=60
80.0% (4/5): item=40 -> result=80
100.0% (5/5): item=50 -> result=100

Completed 5 items.

How it works

The run_with_progress function iterates over items and calls step_callback after each iteration, passing a dictionary with progress details like index, total, and percent. Using a callback decouples the loop logic from how progress is consumed—callers can log to console, update a progress bar, or send events to a UI without modifying the core function. The percent is computed as (idx + 1) / total * 100 and rounded to one decimal place. The function returns the total count so callers know how many items were processed even if the callback is omitted.

Common mistakes

  • Forgetting to check if `step_callback` is provided before calling it, causing TypeError.
  • Using zero-based `idx` as the displayed index, confusing users who expect 1-based numbering.
  • Dividing by total if `items` is empty, leading to ZeroDivisionError.

Variations

  1. Use `tqdm` library for automatic progress bars instead of a custom callback.
  2. Implement the same pattern with a generator that yields progress data for the caller to consume.

Real-world use cases

  • Reporting progress in a data processing ETL job while fetching rows from a database.
  • Updating a web UI progress bar via WebSocket when running long-running background tasks.
  • Logging processing milestones in a machine learning training loop to track epoch progress.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Functions & basics

Related tutorials and quizzes for this topic.