Question bank — f-strings — embedding expressions
Before you start, one picture to keep in your head: an f-string is a story with blanks. The f stamp says "fill the blanks", the { } marks where a blank is, and whatever you write inside a blank is code that runs, not text that prints. Every question below pokes at one of those three parts.
True or false — justify
Every answer explains why — a bare "true/false" earns nothing here.
Adding an f prefix to a string with no braces changes what it prints.
f only activates brace-substitution; with no { } there is nothing to substitute, so f"hi" and "hi" produce the identical text.f"{name}" and "{name}".format(name=name) produce the same output.
.format() argument. See str.format() method.Inside braces you may write a full assignment like {count = count + 1}.
SyntaxError. (The lookalike {count=} with nothing after the = is the unrelated debug form.)The text outside the braces is always printed exactly as typed.
{{ or }} collapses to a single literal { or }, so those four characters do not print as typed.An f-string is a runtime feature that reads variables when the line runs, not when the file is written.
f"{3/0}" will still build a string as long as the syntax is valid.
3/0 raises ZeroDivisionError before any string is produced; valid syntax is not the same as a valid result.The format spec after : changes the value itself, not just how it looks.
F"{x}" (capital F) is a syntax error.
f and uppercase F are valid prefixes and behave identically.Spot the error
Each line has a bug or a surprise. Name it and give the fix.
print("Total: {price}") — expected the number, got the word.
f prefix is missing, so {price} is plain text; it prints Total: {price}. Fix: print(f"Total: {price}").f"He said {"hello"}" breaks on older Python.
" closes the string early on pre-3.12 parsers. Fix: use the other quote inside — f"He said {'hello'}". See Strings — literals and quotes.f"The set is {1, 2, 3}" — you wanted the braces to print.
{ starts an expression, so this actually evaluates the tuple (1, 2, 3) and prints The set is (1, 2, 3). To print literal braces, double them: f"The set is {{1, 2, 3}}".f"{ x = 5 }" — trying to set and show x.
SyntaxError. Do the assignment on its own line first, then use f"{x}" (or f"{x=}" for the debug form).msg = f"Age: {age}" printed the old age even though you changed age later.
msg; changing age afterwards can't reach back into an already-built string. Rebuild the f-string after the update.print(f"{total:.2}") gave odd output for a whole number.
.2 without a type letter means "2 significant digits", not "2 decimal places". For fixed decimals use .2f. See Format specification mini-language.f"{items[0}" — a stray character sneaks in.
} is missing (or ] and } are tangled); the brace never closes, giving a SyntaxError. Every { needs a matching } after a complete expression: f"{items[0]}".Why questions
These test whether you understand the mechanism, not just the syntax.
Why does f"{a + b}" correctly show a number without you calling str()?
format(expr, spec), which defaults to str(expr); the conversion happens automatically after the expression is evaluated. See str() and type conversion.Why can you put a method call like {word.upper()} inside braces but not a for loop?
for loop is a statement with no value, and braces only accept things that evaluate to a result.Why do you double the braces to print a literal brace instead of using a backslash?
{ and } as its own markers, so it uses doubling as its escape rule; \{ isn't recognised — the parser only knows {{ → {.Why does {x=} show x=9 while {x} shows just 9?
= triggers the self-documenting debug form, which prints the source text of the expression plus its value; without the = you get only the value.Why does the literal + in f"{a} + {b}" not get computed?
{ } are treated as code. The interpreter scans left to right and copies out-of-brace characters verbatim.Why is f"{price:,}" clearer than manually inserting commas with string slicing?
Why do we say the f-string "reads left to right"?
{, pausing to parse and evaluate the expression up to the matching } before continuing — a single ordered pass, so order of appearance = order of substitution.Edge cases
The scenarios the happy-path examples skip.
What does an empty f-string f"" produce?
"" — no braces, nothing to fill, so it behaves like any empty string literal.What does f"{''}" (empty string expression inside braces) produce?
'' evaluates to the empty string, which contributes no visible characters, so the whole result is "".What happens with f"{None}"?
None — format(None) falls back to str(None), which is the text "None"; there's no special "blank" behaviour for None.Does f"{x}" work when x is a list, like [1, 2, 3]?
str()-ified, so a list prints as [1, 2, 3]; there's no requirement that the value be a string or number.What if a brace pair contains only whitespace, e.g. f"{ }"?
SyntaxError — an empty (or whitespace-only) expression has nothing to evaluate; the braces must contain a real expression.Can nested braces appear, as in a format spec that uses a variable width f"{val:{width}}"?
{width} is itself evaluated to supply the field width at runtime, letting the format spec be computed rather than hard-coded. See Format specification mini-language.What is printed by f"{{}}" — is it a blank filled with nothing?
{} — the doubled braces are two escapes ({{→{, }}→}), so there is no expression slot here at all, just two literal characters.Recall One-line summary of every trap on this page
The f activates filling · braces hold expressions, not statements · code inside braces runs (and can crash) · doubling escapes literal braces · the spec after : changes looks, not value · substitution happens when the line executes.
Connections
- f-strings — embedding expressions — the parent note these traps are built against.
- str() and type conversion — why no manual
str()is needed inside braces. - str.format() method — the older sibling these questions often contrast with.
- Format specification mini-language — everything after the
:. - Variables and scope — where brace expressions read their values.
- Strings — literals and quotes — the quote-nesting trap.
- print() function — the usual consumer of the finished string.