Python f-strings — 7 Things You Can Do
Video: Python f-strings — 7 Things You Can Do by CelesteAI
An f-string is the modern way to build strings in Python. The f prefix turns the string into a template; anything inside curly braces gets evaluated and dropped in. Most people stop there.
But f-strings have a deeper format-spec mini-language. Number formatting, alignment, percentages, the = debug shortcut, conversion flags, multi-line templates, and date formatting all live inside the same braces. This post walks seven patterns on a tiny demo so you have a mental shelf to reach for next time you build a string.
Setup
from datetime import date
name = "Alice"
price = 1234.5678
count = 42
today = date(2026, 5, 23)
1. Basic interpolation
f"Hello, {name}"
# Hello, Alice
The simplest case. The f prefix makes the string a template; {name} is replaced by the value at runtime.
2. Format spec — numbers, alignment, percentages
f"${price:,.2f}" # $1,234.57 thousand-separator, 2 decimals
f"|{count:>6}|" # | 42| right-pad to width 6
f"{0.1234:.2%}" # 12.34% percentage with 2 decimals
After a colon inside the braces comes the format spec — the same mini-language as the old .format method and the format() built-in. Comma for thousand-separator, .2f for fixed-point with 2 decimals, > for right-align with a width, % for percentage.
This is the part most beginners miss. If you’re calling round() or f"{x:.2f}".rstrip("0") before dropping a number into an f-string, the format spec already does it.
3. Expressions inside the braces — not just variables
items = [10, 20, 30]
f"first: {items[0]}" # first: 10
f"sum: {sum(items)}" # sum: 60
f"upper: {name.upper()}" # upper: ALICE
Anything that evaluates to a value works inside the braces. Method calls. Indexing. Arithmetic. Even ternary expressions and small comprehensions (though the readability of those drops fast).
4. = for debugging (Python 3.8+)
x, y = 10, 20
f"{x=}, {y=}, {x+y=}"
# x=10, y=20, x+y=30
The killer feature for print-debugging. {x=} prints both the expression and its value, separated by =. Saves you from typing the variable name twice — once as a label and once as the value. Works for any expression: {items[0]=}, {sum(items)=}, {x*y=}.
If you’re scattering print(f"x is {x}") calls through your code to figure out what’s wrong, switch to print(f"{x=}") and you’ll see why people love it.
5. !r / !s / !a conversion flags
words = ["python", "lambda"]
f"with str: {words!s}" # ['python', 'lambda']
f"with repr: {words!r}" # ['python', 'lambda'] (same here)
f"with ascii: {'café'!a}" # 'caf\xe9'
The bang flags call str(), repr(), or ascii() on the value before formatting. !r is the most useful in practice: it quotes strings in the output, so in debug logs you can tell "" from None and the string "5" from the number 5.
6. Multi-line f-strings
msg = f"""
=== Report ===
name: {name}
price: ${price:,.2f}
date: {today}
"""
Triple-quote and embed values across multiple lines. Useful for printing structured reports, building config blocks, or producing multi-line error messages.
7. Date and time formatting — strftime codes inside the spec
f"{today:%Y-%m-%d}" # 2026-05-23
f"{today:%A, %B %d %Y}" # Saturday, May 23 2026
The format spec accepts strftime codes for date and datetime values. No need to call today.strftime(...) separately and then drop the result into a regular string. Same story for % (percentage), x (hex), b (binary), e (scientific) — all the format codes from the spec mini-language work here.
The decision
| Goal | Pattern |
|---|---|
| Drop a variable in | f"{x}" |
| Number formatting | f"{x:,.2f}", f"{x:.2%}" |
| Method call / expression | f"{x.upper()}", f"{sum(xs)}" |
| Print-debugging | f"{x=}" |
| Quoted in logs | f"{x!r}" |
| Multi-line | f"""...""" |
| Date | f"{date:%Y-%m-%d}" |
Once you’ve internalized these seven, almost every Python string-building task fits one of them.
Want the deeper dive?
Common Questions Ep 12 — List Comprehensions is a similar “patterns you’ll meet in real code” walk-through for another Python idiom.