How to Overwrite Print Output in Python

Learn how to overwrite print output in Python using carriage return for single-line updates and ANSI escape sequences for multi-line overwrites.

How to Overwrite Print Output in Python

Overwriting a Single Line

To overwrite a single line, use \r (carriage return). This control character moves the cursor to the beginning of the current line.

print("\r" + "Overwriting a single line!", end="")

Use end="" to prevent a newline character from being printed, keeping the cursor on the same line.

Countdown Timer Example

Here is a practical use of \r to implement a countdown timer.

import time
import sys

def countdown(seconds):
    for i in range(seconds, 0, -1):
        # \r returns to the start of the line, overwriting previous output
        sys.stdout.write(f"\rTime remaining: {i:3d} seconds")
        sys.stdout.flush()
        time.sleep(1)
    sys.stdout.write("\rDone!                      \n")

countdown(10)

Here we use sys.stdout.write and sys.stdout.flush(). While print internally calls sys.stdout.write, using sys.stdout directly gives more explicit control over buffering. Calling flush() ensures that output is immediately displayed on screen.

Note: If the new string is shorter than the previous one, leftover characters from the previous output will remain visible. In the example above, spaces are added after "Done!" to ensure the previous text is fully cleared.

Spinning Cursor Implementation

A spinning cursor (loading animation) that visually indicates ongoing processing can also be implemented with \r.

import sys
import time
import itertools

def spinning_cursor(duration=5):
    spinner = itertools.cycle(['|', '/', '-', '\\'])
    end_time = time.time() + duration
    while time.time() < end_time:
        sys.stdout.write(f"\rProcessing... {next(spinner)}")
        sys.stdout.flush()
        time.sleep(0.1)
    sys.stdout.write("\rComplete!          \n")

spinning_cursor(3)

Using itertools.cycle allows the spinner characters to repeat indefinitely.

Overwriting Multiple Lines

To overwrite multiple lines, you can use special ANSI escape codes. The sequence \033[nA moves the cursor up n lines.

import time

print("First line")
print("Second line")
print("Third line")

time.sleep(1) # Wait for a second to see the initial output

# Move cursor up 2 lines (from the current position, which is after "Third line")
# and then overwrite the second and third lines.
print("\033[2A" + "New Second line\n" + "New Third line")

ANSI Escape Sequence Reference

Here is a summary of the main ANSI escape sequences for cursor control and text decoration in the terminal.

Cursor Control

SequenceDescriptionExample
\033[nAMove cursor up n linesprint("\033[2A")
\033[nBMove cursor down n linesprint("\033[1B")
\033[nCMove cursor right n columnsprint("\033[5C")
\033[nDMove cursor left n columnsprint("\033[3D")
\033[2KClear current lineprint("\033[2K", end="")
\033[JClear from cursor to endprint("\033[J", end="")
\033[HMove cursor to top-leftprint("\033[H")
\033[{r};{c}HMove cursor to row r, column cprint("\033[5;10H")

Text Decoration (Colors & Styles)

SequenceDescription
\033[0mReset (clear all)
\033[1mBold
\033[4mUnderline
\033[31mRed text
\033[32mGreen text
\033[33mYellow text
\033[34mBlue text
\033[41mRed background
\033[42mGreen background

For example, colored status messages can be written as follows.

# Display in green for success, red for failure
def print_status(message, success=True):
    color = "\033[32m" if success else "\033[31m"
    reset = "\033[0m"
    print(f"{color}{message}{reset}")

print_status("Test passed", success=True)
print_status("Test failed", success=False)

Download Progress Bar Example

By combining \r and ANSI escape sequences, you can build a practical download progress display.

import sys
import time

def download_progress(total_size, chunk_size=1024):
    """Display download progress with a progress bar"""
    downloaded = 0
    bar_length = 40

    while downloaded < total_size:
        downloaded += chunk_size
        if downloaded > total_size:
            downloaded = total_size

        # Calculate progress
        progress = downloaded / total_size
        filled = int(bar_length * progress)
        bar = "█" * filled + "░" * (bar_length - filled)

        # Display in MB
        dl_mb = downloaded / (1024 * 1024)
        total_mb = total_size / (1024 * 1024)

        # Color-coded progress
        if progress < 0.5:
            color = "\033[33m"  # Yellow
        else:
            color = "\033[32m"  # Green
        reset = "\033[0m"

        sys.stdout.write(
            f"\r{color}[{bar}]{reset} "
            f"{progress:6.1%} "
            f"({dl_mb:.1f}/{total_mb:.1f} MB)"
        )
        sys.stdout.flush()
        time.sleep(0.01)  # Simulate download

    sys.stdout.write("\n")
    print("Download complete!")

# Simulate a 10MB file download
download_progress(10 * 1024 * 1024, chunk_size=100 * 1024)

Multi-Line Real-Time Update Example

By combining ANSI escape sequences, you can update the progress of multiple tasks simultaneously in real time.

import sys
import time
import random

def multi_task_progress():
    """Update progress for multiple tasks simultaneously"""
    tasks = ["Fetching ", "Preprocess", "Training  ", "Evaluation"]
    progress = [0] * len(tasks)

    # Initial display
    for task in tasks:
        print(f"  {task}: [{'░' * 30}]   0%")

    while not all(p >= 100 for p in progress):
        # Randomly advance progress
        for i in range(len(tasks)):
            if progress[i] < 100:
                progress[i] = min(100, progress[i] + random.randint(0, 5))

        # Move cursor up by the number of tasks
        sys.stdout.write(f"\033[{len(tasks)}A")

        for i, task in enumerate(tasks):
            filled = int(30 * progress[i] / 100)
            bar = "█" * filled + "░" * (30 - filled)
            if progress[i] >= 100:
                color = "\033[32m"  # Complete: green
            else:
                color = "\033[33m"  # In progress: yellow
            reset = "\033[0m"
            print(f"  {task}: {color}[{bar}]{reset} {progress[i]:3d}%")

        time.sleep(0.1)

multi_task_progress()

Cross-Platform Considerations

ANSI escape sequences work natively on Linux and macOS terminals, but the traditional Windows Command Prompt (cmd.exe) does not support them.

Handling Windows

Windows Terminal and PowerShell on Windows 10+ do support ANSI escape sequences, but for compatibility with older environments, use the colorama library.

# pip install colorama
from colorama import init, Fore, Style

# Enable ANSI escapes on Windows
init()

# Colored output with colorama
print(Fore.GREEN + "Success" + Style.RESET_ALL)
print(Fore.RED + "Error" + Style.RESET_ALL)

Simply calling colorama.init() makes ANSI escape sequences work correctly on Windows. On Linux/macOS it does nothing (no side effects), making it suitable for cross-platform code.

Branching with os.name

If you prefer not to use colorama, you can branch based on os.name.

import os
import sys

def supports_ansi():
    """Check if the terminal supports ANSI escape sequences"""
    if os.name == "nt":
        # Supported on Windows 10 build 10586+
        return os.environ.get("WT_SESSION") is not None  # Windows Terminal
    return hasattr(sys.stdout, "isatty") and sys.stdout.isatty()

if supports_ansi():
    GREEN = "\033[32m"
    RESET = "\033[0m"
else:
    GREEN = ""
    RESET = ""

print(f"{GREEN}Status: OK{RESET}")

Library Comparison: Manual vs tqdm vs rich

Choose the right approach based on your use case.

FeatureManual (\r / ANSI)tqdmrich
External dependencyNonepip installpip install
Progress barMust build yourselfOne-linerOne-liner
Multiple barsMust build yourselfSupportedSupported
Table displayNot availableNot availableSupported
Colored outputManual ANSI codesLimitedEasy with Rich Markup
Windows supportNeeds coloramaAutomaticAutomatic
CustomizabilityFull controlModerateHigh
Learning curveLow (good for learning)LowModerate
Best forLightweight, learningLoop processingRich CLI applications

For simple overwrite displays, use the techniques from this article. For progress bars in loops, consider tqdm. For rich CLI applications, consider rich.

Modern Python Output Libraries

Beyond overwriting print output, there are libraries that provide rich terminal output.

The rich Library

rich can display colored text, tables, progress bars, and more in the terminal.

from rich.console import Console
from rich.table import Table

console = Console()

# Progress display
from rich.progress import track
import time

for i in track(range(100), description="Processing..."):
    time.sleep(0.01)

# Status display (with spinner)
with console.status("Computing..."):
    time.sleep(2)
    console.print("[bold green]Done![/bold green]")

Progress Bars with tqdm

tqdm provides progress bars with minimal code. It is widely used as an alternative to manual overwrite-based displays.

from tqdm import tqdm
import time

for i in tqdm(range(100)):
    time.sleep(0.01)