Everything after the colon inside { } is a format spec. Learn five of them and you stop writing round(), str() and manual padding to make output readable.
Numbers
revenue = 1234567.891 share = 0.3456 print(f"{revenue:,.2f}") print(f"{share:.1%}") print(f"{revenue:_.0f}")
1,234,567.89 34.6% 1_234_568
, adds thousands separators, .2f means two decimals, % multiplies by 100 and adds the sign, and _ uses underscores, the way you'd write the number in Python code.
Columns
< left-aligns, > right-aligns, and the number is the width:
rows = [("Tea", 2.5, 120), ("Coffee", 3.75, 86), ("Hot chocolate", 4.2, 15)] for name, price, sold in rows: print(f"{name:<14}{price:>6.2f}{sold:>5}")
Tea 2.50 120 Coffee 3.75 86 Hot chocolate 4.20 15
A readable table, with no padding code at all.
Dates
A date takes the same codes as strftime, right in the braces:
from datetime import date d = date(2026, 9, 29) print(f"{d:%d %b %Y}") print(f"{d:%A}")
29 Sep 2026 Tuesday
Debugging with =
Put = after an expression and the f-string prints the expression too:
share = 0.3456 print(f"{share=}") print(f"{share * 100 = :.1f}")
share=0.3456 share * 100 = 34.6
Why it works
Each value's type decides what its format spec means: numbers understand , and f, dates understand %Y. The f-string passes the text after the colon to format(value, spec), which calls the type's __format__.
When not to use it
Format for display, not for storage: f"{price:.2f}" is a string, and doing maths on it later means parsing it back. Keep the number, format at the edge. And for money that must be exact, round with Decimal first; .2f rounds binary floats, which can surprise you on halves.