Python Basics — String Formatting Deep Dive

3 minute read

String Formatting Deep Dive

Beyond f-strings and str.format(), Python offers additional formatting tools for specialized needs.

Template Strings

The string module provides Template — a simpler, safer alternative for user-provided templates:

from string import Template

t = Template("Hello, $name! You have $count messages.")
result = t.substitute(name="Alice", count=5)
print(result)  # Hello, Alice! You have 5 messages.

safe_substitute()

Won’t raise an error for missing placeholders:

from string import Template

t = Template("Hello, $name! Your role is $role.")
print(t.safe_substitute(name="Alice"))
# Hello, Alice! Your role is $role.

When to Use Template Strings

  • User-supplied format strings (prevents code injection)
  • Simple key-value replacement
  • When you don’t need expressions or format specs
# f-strings can execute code — risky with user input
# template = f"{user_input}"  # DANGER if user_input is malicious

# Template strings are safe
from string import Template
t = Template(user_input)  # Only does simple substitution

textwrap Module

For formatting paragraphs and indented text:

import textwrap

long_text = "Python is a versatile programming language that is widely used in web development, data science, artificial intelligence, and automation. It was created by Guido van Rossum and first released in 1991."

# Wrap to 40 characters
wrapped = textwrap.fill(long_text, width=40)
print(wrapped)

Output:

Python is a versatile programming
language that is widely used in web
development, data science, artificial
intelligence, and automation. It was
created by Guido van Rossum and first
released in 1991.

textwrap Functions

import textwrap

text = "    Hello, World!    "

# Remove common leading whitespace
code = """
    def hello():
        print("hi")
"""
print(textwrap.dedent(code))

Output:


def hello():
    print("hi")

import textwrap

# Indent every line
text = "Line 1\nLine 2\nLine 3"
print(textwrap.indent(text, ">>> "))

Output:

>>> Line 1
>>> Line 2
>>> Line 3
import textwrap

# Shorten (truncate with placeholder)
long = "This is a very long string that needs to be shortened"
print(textwrap.shorten(long, width=30))
# This is a very long [...]

Building Formatted Tables

Simple Table with f-strings

data = [
    ("Product", "Price", "Qty"),
    ("Widget", 9.99, 100),
    ("Gadget", 24.95, 50),
    ("Doohickey", 4.50, 200),
]

# Header
h = data[0]
print(f"{h[0]:<12} {h[1]:>8} {h[2]:>5}")
print("-" * 27)

# Rows
for name, price, qty in data[1:]:
    print(f"{name:<12} ${price:>7.2f} {qty:>5}")

Output:

Product         Price   Qty
---------------------------
Widget        $  9.99   100
Gadget        $ 24.95    50
Doohickey     $  4.50   200

Dynamic Column Widths

data = [
    ["Alice", "Engineering", 95000],
    ["Bob", "Marketing", 72000],
    ["Charlie", "Engineering", 105000],
    ["Diana", "Sales", 68000],
]

headers = ["Name", "Department", "Salary"]

# Calculate column widths dynamically
widths = [len(h) for h in headers]
for row in data:
    for i, val in enumerate(row):
        widths[i] = max(widths[i], len(str(val)))

# Print with calculated widths
header_fmt = " | ".join(f"{h:<{widths[i]}}" for i, h in enumerate(headers))
print(header_fmt)
print("-+-".join("-" * w for w in widths))

for row in data:
    row_fmt = " | ".join(f"{str(v):<{widths[i]}}" for i, v in enumerate(row))
    print(row_fmt)

Output:

Name    | Department  | Salary
--------+-------------+-------
Alice   | Engineering | 95000
Bob     | Marketing   | 72000
Charlie | Engineering | 105000
Diana   | Sales       | 68000

String Alignment and Padding

Using str methods

# center(), ljust(), rjust()
title = "REPORT"
print(title.center(30, "="))   # ============REPORT============
print(title.ljust(30, "-"))    # REPORT------------------------
print(title.rjust(30, "."))    # ........................REPORT

Using format spec

# Same results with f-strings
print(f"{'REPORT':=^30}")    # ============REPORT============
print(f"{'REPORT':-<30}")    # REPORT------------------------
print(f"{'REPORT':.>30}")    # ........................REPORT

Multiline String Formatting

name = "Alice"
role = "Developer"
years = 5

profile = (
    f"{'Name:':<10} {name}\n"
    f"{'Role:':<10} {role}\n"
    f"{'Years:':<10} {years}\n"
)
print(profile)

Output:

Name:      Alice
Role:      Developer
Years:     5

Internationalization Considerations

Number Formatting by Locale

import locale

# Set locale (varies by system)
# locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')

# Manual formatting for different conventions
num = 1234567.89

# US style
print(f"US: {num:,.2f}")       # 1,234,567.89

# European style (manual)
us_format = f"{num:,.2f}"
eu_format = us_format.replace(",", "X").replace(".", ",").replace("X", ".")
print(f"EU: {eu_format}")      # 1.234.567,89

Unicode in Strings

# Python 3 strings are Unicode by default
emoji = "Python is fun! 🐍"
print(emoji)

# Unicode escape
print("\u2764")      # ❤
print("\U0001F600")  # 😀

Summary

  • Template strings are safer for user-provided format patterns
  • textwrap handles paragraph wrapping, indentation, and truncation
  • Build tables with format specs and calculated column widths
  • Use center(), ljust(), rjust() or format specs for alignment
  • Python 3 strings are Unicode by default — emoji and special chars work natively
  • Use locale module for region-specific number formatting

Next up: Regular Expressions Intro →

Updated: