Data formatting
Tabular data
Printing lists
Data visualization
Python programming

Printing Lists as Tabular Data

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

Displaying list data in aligned columns makes it far easier to read than raw print output. Python offers several approaches — from built-in string formatting to dedicated libraries like tabulate and pandas. The right choice depends on whether you need quick console output, export to other formats, or full data analysis capabilities.

Method 1: String Formatting with f-strings

The simplest approach uses Python's string formatting to align columns:

python
1headers = ["Name", "Age", "City"]
2data = [
3    ["Alice", 30, "New York"],
4    ["Bob", 25, "San Francisco"],
5    ["Charlie", 35, "Chicago"],
6]
7
8# Print header
9print(f"{'Name':<15} {'Age':<6} {'City':<15}")
10print("-" * 36)
11
12# Print rows
13for row in data:
14    print(f"{row[0]:<15} {row[1]:<6} {row[2]:<15}")
15
16# Output:
17# Name            Age    City
18# ------------------------------------
19# Alice           30     New York
20# Bob             25     San Francisco
21# Charlie         35     Chicago

Format specifiers: < left-aligns, > right-aligns, ^ centers. The number sets the field width.

Method 2: The tabulate Library

tabulate is the go-to library for console tables with minimal code:

python
1from tabulate import tabulate
2
3headers = ["Name", "Age", "City"]
4data = [
5    ["Alice", 30, "New York"],
6    ["Bob", 25, "San Francisco"],
7    ["Charlie", 35, "Chicago"],
8]
9
10print(tabulate(data, headers=headers, tablefmt="grid"))
11# +---------+-----+---------------+
12# | Name    | Age | City          |
13# +=========+=====+===============+
14# | Alice   |  30 | New York      |
15# +---------+-----+---------------+
16# | Bob     |  25 | San Francisco |
17# +---------+-----+---------------+
18# | Charlie |  35 | Chicago       |
19# +---------+-----+---------------+

Available formats include grid, pipe (Markdown), html, latex, plain, simple, and fancy_grid:

python
1# Markdown-compatible output
2print(tabulate(data, headers=headers, tablefmt="pipe"))
3# | Name    |   Age | City          |
4# |:--------|------:|:--------------|
5# | Alice   |    30 | New York      |
6# | Bob     |    25 | San Francisco |
7# | Charlie |    35 | Chicago       |
8
9# Install: pip install tabulate

Method 3: Using pandas DataFrame

For data analysis workflows, pandas provides built-in table display:

python
1import pandas as pd
2
3data = {
4    "Name": ["Alice", "Bob", "Charlie"],
5    "Age": [30, 25, 35],
6    "City": ["New York", "San Francisco", "Chicago"],
7}
8
9df = pd.DataFrame(data)
10print(df)
11#       Name  Age           City
12# 0    Alice   30       New York
13# 1      Bob   25  San Francisco
14# 2  Charlie   35        Chicago
15
16# Convert to various formats
17print(df.to_markdown())      # Markdown table
18print(df.to_html())          # HTML table
19print(df.to_latex())         # LaTeX table
20print(df.to_string(index=False))  # No index column

Method 4: str.format with Dynamic Widths

Calculate column widths automatically from the data:

python
1def print_table(headers, data):
2    # Calculate the maximum width for each column
3    widths = [len(h) for h in headers]
4    for row in data:
5        for i, cell in enumerate(row):
6            widths[i] = max(widths[i], len(str(cell)))
7
8    # Build format string
9    fmt = " | ".join(f"{{:<{w}}}" for w in widths)
10    separator = "-+-".join("-" * w for w in widths)
11
12    print(fmt.format(*headers))
13    print(separator)
14    for row in data:
15        print(fmt.format(*[str(c) for c in row]))
16
17headers = ["Product", "Price", "Stock"]
18data = [
19    ["Widget", 9.99, 150],
20    ["Gadget Pro", 49.99, 23],
21    ["Thingamajig", 4.50, 500],
22]
23
24print_table(headers, data)
25# Product     | Price | Stock
26# -----------+-------+------
27# Widget      | 9.99  | 150
28# Gadget Pro  | 49.99 | 23
29# Thingamajig | 4.50  | 500

Method 5: PrettyTable

Another dedicated library with an interactive feel:

python
1from prettytable import PrettyTable
2
3table = PrettyTable()
4table.field_names = ["Name", "Age", "City"]
5table.add_row(["Alice", 30, "New York"])
6table.add_row(["Bob", 25, "San Francisco"])
7table.add_row(["Charlie", 35, "Chicago"])
8
9table.align["Name"] = "l"  # Left align
10table.align["Age"] = "r"   # Right align
11
12print(table)
13# +---------+-----+---------------+
14# | Name    | Age | City          |
15# +---------+-----+---------------+
16# | Alice   |  30 | New York      |
17# | Bob     |  25 | San Francisco |
18# | Charlie |  35 | Chicago       |
19# +---------+-----+---------------+
20
21# Sort by column
22table.sortby = "Age"
23print(table)

Method 6: CSV Module for File Output

When you need to write tabular data to a file:

python
1import csv
2import io
3
4headers = ["Name", "Age", "City"]
5data = [["Alice", 30, "New York"], ["Bob", 25, "Chicago"]]
6
7# Write to CSV file
8with open("output.csv", "w", newline="") as f:
9    writer = csv.writer(f)
10    writer.writerow(headers)
11    writer.writerows(data)
12
13# Print as CSV to console
14output = io.StringIO()
15writer = csv.writer(output)
16writer.writerow(headers)
17writer.writerows(data)
18print(output.getvalue())

Common Pitfalls

  • Mixed types break alignment: Numbers and strings have different default alignments. Convert everything to strings with str() before formatting, or use tabulate which handles this automatically.
  • Unicode characters break column widths: Characters like CJK ideographs are double-width in terminals. len("日本") returns 2 but displays as 4 characters wide. Use unicodedata.east_asian_width() or wcwidth library for accurate widths.
  • Large datasets flood the console: For tables with hundreds of rows, use df.head() / df.tail() with pandas, or pipe output through a pager like less.
  • Forgetting newline="" in CSV: On Windows, omitting newline="" in open() causes double line breaks in CSV files.
  • Hardcoded column widths: Hardcoding widths like f"{name:20}" breaks when data exceeds the width. Calculate widths dynamically from the data.

Summary

  • Use f-strings or str.format() for quick, dependency-free console output
  • Use tabulate for formatted tables with multiple output formats (grid, Markdown, HTML, LaTeX)
  • Use pandas.DataFrame when you are already doing data analysis
  • Use PrettyTable for interactive table building with sorting and alignment
  • Calculate column widths dynamically from your data to handle variable-length content
  • For file output, use the csv module or df.to_csv()

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

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

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.