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, and format it only when you display it. And for money that must be exact, round with Decimal first, because .2f rounds binary floats, which can surprise you on halves.