Python f-string Number Formatting
The format spec inside a Python f-string controls decimals, thousands separators, percentages, padding, and sign — all in a single colon-delimited expression: f"{value:[fill][align][sign][#][0][width][,][.precision][type]}". This page is the cheat sheet you can copy from.
How to Format Decimal Places in a Python f-string
pi = 3.14159265359
f"{pi:.2f}" # '3.14'
f"{pi:.4f}" # '3.1416'
f"{pi:.0f}" # '3' (rounded to integer, still a string)
# Round-half-to-even (banker's rounding) is used:
f"{2.5:.0f}" # '2'
f"{3.5:.0f}" # '4'
How to Format Floats vs Integers
# f = fixed-point float
f"{1234.5:.2f}" # '1234.50'
# d = integer (errors on a float)
f"{1234:d}" # '1234'
# f"{1234.5:d}" -> ValueError
# g = general (drops trailing zeros, switches to scientific for big/small)
f"{1234.5:g}" # '1234.5'
f"{0.000012345:g}" # '1.2345e-05'
How to Add Thousands Separators
amount = 1234567.891
f"{amount:,}" # '1,234,567.891'
f"{amount:,.2f}" # '1,234,567.89'
f"{amount:_.2f}" # '1_234_567.89' (PEP 515 underscore separator)
# Locale-aware (uses LC_NUMERIC) — useful for European-style 1.234.567,89:
f"{amount:n}" # depends on locale.setlocale()
How to Format Percentages
ratio = 0.0857
f"{ratio:.0%}" # '9%' (0.0857 -> 8.57 -> rounds to 9)
f"{ratio:.1%}" # '8.6%'
f"{ratio:.2%}" # '8.57%'
# Already a percent? Use f and append the symbol manually:
pct = 8.57
f"{pct:.2f}%" # '8.57%'
Width, Padding, and Alignment
n = 42
f"{n:5d}" # ' 42' (width 5, right-aligned by default for numbers)
f"{n:<5d}" # '42 ' (left-align)
f"{n:^5d}" # ' 42 ' (center)
f"{n:05d}" # '00042' (zero-pad)
f"{n:>5d}" # ' 42' (right-align, explicit)
# Custom fill character:
f"{n:*^7d}" # '**42***'
# Combine with thousands and decimals:
f"{1234.5:>12,.2f}" # ' 1,234.50'
Forcing the Sign
x = 42
y = -42
f"{x:+d}" # '+42' (always show sign)
f"{y:+d}" # '-42'
f"{x: d}" # ' 42' (space for positives, '-' for negatives — aligns columns)
f"{x:-d}" # '42' (default: only show '-')
Scientific Notation and Hex/Binary
tiny = 0.000001234
f"{tiny:.2e}" # '1.23e-06'
f"{tiny:.2E}" # '1.23E-06'
# Integer bases:
f"{255:b}" # '11111111' binary
f"{255:o}" # '377' octal
f"{255:x}" # 'ff' hex (lowercase)
f"{255:X}" # 'FF' hex (uppercase)
f"{255:#x}" # '0xff' with prefix
The Format Spec, in Order
Every piece is optional, but they must appear in this order after the colon:
{value:[fill][align][sign][#][0][width][,][.precision][type]}
# Worked example — fill='0', align='>', width=8, comma, .2f:
f"{1234.5:0>8,.2f}" # '1,234.50' (already 8 chars, no fill added)
f"{12.5:0>8,.2f}" # '00012.50'
Common Pitfalls
- Mixing types:
f"{1234:.2f}"works (Python coerces int to float), butf"{1234.5:d}"raisesValueError. - Rounding surprises: Python uses banker's rounding (round-half-to-even). For accounting, use
decimal.DecimalwithROUND_HALF_UP. - Percent doubles the value:
:.0%multiplies by 100. Don't apply it to a number that's already in percent units. - Width includes the separator and decimal point:
f"{1234.5:8,.2f}"produces an 8-char string total, not 8 digits.
Pro Tip: Need a dynamic precision? You can nest a variable into the spec: f"{value:.{n}f}" formats with n decimal places, where n is computed at runtime.