🐍 Python Everyday — ✨ F-Strings: From Messy Output to Clean Reports
Posted on: October 31, 2026
Description:
A useful script should produce output that is easy to read. Python f-strings let us insert values into text and control their presentation. In this episode, three formatting choices turn sample folder sizes into a small report.
1. Start with the raw values
rows = [("Images", 12345.678), ("Logs", 987.6), ("Cache", 42.0)]
for name, size in rows:
print(name, size)
Output:
Images 12345.678
Logs 987.6
Cache 42.0
The values are valid, but their decimal places and starting positions vary. These are illustrative sizes in kilobytes.
2. Set decimal precision and grouping
size = 12345.678
print(f"{size:.2f}") # 12345.68
print(f"{size:,.2f}") # 12,345.68
The colon introduces a format specification. Here, .2f displays two digits after the decimal point, and , groups the integer part into thousands. The result is rounded display text; size remains unchanged. Comma grouping is explicit, not locale-aware. Python format specification documentation.
3. Align the fields
for name, size in rows:
print(f"{name:<10} {size:>12,.2f}")
Read the two fields as:
| Field | Meaning |
|---|---|
{name:<10} |
Left-align the name in a minimum width of 10 |
{size:>12,.2f} |
Right-align the formatted number in a minimum width of 12, with grouping and two decimal places |
Numeric width includes the digits, comma and decimal point. The space between fields separates the columns. These alignment rules are defined in Python's format mini-language.
4. Print the complete report
print(f"{'Folder':<10} {'Size (KB)':>12}")
print("-" * 23)
for name, size in rows:
print(f"{name:<10} {size:>12,.2f}")
Folder Size (KB)
-----------------------
Images 12,345.68
Logs 987.60
Cache 42.00
View the output in a monospaced font. The accompanying commented Python script builds this report and includes assertions for the examples. It runs with Python 3.6+ and needs no external packages.
5. Remember the boundaries
Width is a minimum, not a truncation rule: a name longer than ten characters will extend beyond that field. For larger reports, choose widths based on the actual content. This example uses simple ASCII labels; wide Unicode characters may need special handling for terminal alignment.
Formatting controls presentation. It does not change the stored value or fix floating-point arithmetic. Keep calculations numeric and format at the point where you display results.
Code Snippet:
# 1. Sample data: labels and illustrative sizes in kilobytes.
ROWS = [("Images", 12345.678), ("Logs", 987.6), ("Cache", 42.0)]
def build_report(rows):
"""Return a small, plain-text report for a monospaced display."""
# <10: left-align in a minimum width of 10 characters.
# >12: right-align in a minimum width of 12 characters.
lines = [f"{'Folder':<10} {'Size (KB)':>12}", "-" * 23]
for name, size in rows:
# , groups thousands; .2f displays two digits after the decimal point.
lines.append(f"{name:<10} {size:>12,.2f}")
return "\n".join(lines)
def main():
# 2. Raw output has uneven columns and decimal precision.
print("BEFORE")
for name, size in ROWS:
print(name, size)
# 3. A colon introduces formatting rules inside an f-string field.
size = ROWS[0][1]
print("\nONE VALUE, STEP BY STEP")
print(f"Raw: {size}") # 12345.678
print(f"Two places: {size:.2f}") # 12345.68
print(f"Grouped: {size:,.2f}") # 12,345.68
# 4. Combine text alignment and numeric formatting into a report.
print("\nAFTER")
print(build_report(ROWS))
# 5. Formatting returns text; the original numeric value is unchanged.
formatted = f"{size:,.2f}"
assert formatted == "12,345.68"
assert size == 12345.678
assert f"{42.0:,.2f}" == "42.00"
assert f"{-1234.5:,.2f}" == "-1,234.50"
assert build_report(ROWS).splitlines()[2] == "Images 12,345.68"
# Width is a MINIMUM, not a limit: longer content is not truncated.
assert f"{'VeryLongFolder':<10}" == "VeryLongFolder"
# Fixed widths suit this small ASCII example; use wider/dynamic fields
# for longer values. Comma grouping here is not locale-aware.
if __name__ == "__main__":
main()
No comments yet. Be the first to comment!