f-strings (string interpolation)
An f-string lets you build a string with values dropped straight into it. You put the letter f immediately before the opening quote, then write {expression} anywhere inside; Python evaluates each {...} and slots the result into the text.
The expression in the braces can be a variable, a calculation, or a function call — anything that produces a value. This beats gluing strings together with + (which needs every piece to already be a string and gets unreadable fast).
f-strings were added in Python 3.6 and are the standard way to format text today.
Syntax
f"text {expression} more text"
name = "Sam"
f"Welcome, {name}" # "Welcome, Sam"
f"Total: {2 + 3}" # "Total: 5"
f"{name} has {len(name)} letters"Worked examples
Dropping variables into text
name = "Sam"
level = 4
print(f"Welcome, {name} — you're on level {level}")
# Output:
# Welcome, Sam — you're on level 4Expressions inside the braces
price = 20
qty = 3
print(f"Total: {price * qty}")
# Output:
# Total: 60Number formatting with a format spec
ratio = 0.8423
print(f"{ratio:.1%}") # 84.2%
print(f"{1234567:,}") # 1,234,567
print(f"{3.14159:.2f}") # 3.14Common mistakes & gotchas
Forgetting the f
Without the leading f, the braces are taken literally: "hi {name}" prints the characters {name}, not the value. The f is what turns braces into slots.
Quote clashes inside the braces
In older Pythons you couldn't reuse the same quote type inside an f-string's braces. In 3.12+ you can (f"{d["key"]}" works), but to stay portable, use the other quote style inside: f"{d['key']}".
An f-string is still just text
f"{1 + 1}" produces the *string* "2", not the number 2. If you need the number, don't wrap it in an f-string.
Why it matters
Almost every program builds text from data — log lines, messages, file names, API responses. f-strings make that readable and hard to get wrong, which is why they're everywhere in real codebases.