039. Formatting Output
Align and format values for readability
039. Formatting Output
RAM Manager: Process Table Display
Aryan wants his RAM manager to print a table like ps aux β perfectly aligned columns regardless of process name length:
chrome [ 812] 544MB 6.8%
python3 [ 421] 398MB 4.9%
Slack [ 234] 256MB 3.2%Without format specifiers, long names push other columns off alignment. The {x:<15} (left-align in 15 chars), {n:>6} (right-align in 6 chars), and {f:.1f} (1 decimal) specs give him pixel-perfect columns.
The broken code has no format specs at all β just raw values crammed together β and format_currency shows $1234.56 without the thousands comma.
π‘ Fun fact: Pythonβs format specification mini-language (the :<15, :,.2f syntax) is directly inspired by the printf format strings from C, but extended with alignment, fill characters, and the , thousands separator. The , separator alone was added in Python 2.7 (2010) specifically because so many developers were manually formatting currency β it was one of the most requested features at the time.
β οΈ Watch out: f"{value:.1%}" and f"{value:.1f}%" look similar but behave very differently β :.1% multiplies by 100 automatically, so you pass 0.75 to get "75.0%", while :.1f% expects you to pass 75.0 already. Mixing these up produces values that are off by a factor of 100 with no error message.
π€ Think about it: f"{name:<15}" pads name to 15 characters with spaces on the right. What happens if name is longer than 15 characters β does it truncate, overflow, or something else? How would you enforce a hard maximum column width in a table where process names could be arbitrarily long?
Learning objectives
- Align text with < > ^ alignment specifiers
- Format numbers with thousands separator (,) and decimal places (.Nf)
- Use format specs for clean tabular output
Key concepts
- format specifiers
- alignment
- number formatting
Try it
Concept detail
f-string format specifiers follow the format: {value:[[fill]align][width][,][.precision][type]}
Alignment: {x:<15} left-align in 15 chars (default for strings) {x:>10} right-align in 10 chars (default for numbers) {x:^20} center in 20 chars {x:*>10} right-align, pad with * instead of spaces
Number formatting: {n:,} thousands separator β 1,000,000 {f:.2f} 2 decimal places β 3.14 {n:05d} zero-padded integer β 00042 {n:,.2f} both thousands separator AND 2 decimals β 1,234.56 {f:.1%} percentage (multiplies by 100) β β75.0%β (note: f=0.75 not 75)
Combined: {n:>10,.2f} right-align 10 wide, thousands, 2 decimals
These same specs work in str.format(): β{:,.2f}β.format(1234.5) And in % formatting (older): β%.2fβ % 3.14
Solution
def format_row(name, score, grade):
return f"{name:<15}{score:>5} {grade}"
def format_currency(amount):
return f"${amount:,.2f}"
def format_percent(value, total):
pct = value / total * 100
return f"{pct:.1f}%"Tests
def test_format_row_alignment():
result = format_row("Alice", 95, "A")
assert result.startswith("Alice")
assert "95" in result
assert "A" in result
assert len(result) >= 20, "Row must be padded to fixed width"
def test_format_row_name_padded():
short = format_row("Al", 95, "A")
long_name = format_row("Alexander", 95, "A")
# Score position should be consistent regardless of name length
assert short.index("95") == long_name.index("95"), "Score column not aligned"
def test_format_currency():
assert format_currency(1234.56) == "$1,234.56"
def test_format_currency_thousands():
assert format_currency(1000000) == "$1,000,000.00"
def test_format_currency_no_thousands():
result = format_currency(1234.56)
assert "," in result, "Missing thousands separator β use :,.2f"
def test_format_percent():
result = format_percent(3, 4)
assert result == "75.0%"
def test_format_percent_precision():
result = format_percent(1, 3)
assert result == "33.3%", f"Got {repr(result)} β use :.1f for 1 decimal place"