We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Modern Syntax and Modernisation step 9 of 18
PEP 701: what f-strings can finally do in 3.12
Before 3.12 the f-string grammar was a separate, hand-written parser bolted onto the tokenizer. It could not see a backslash, could not reuse the quote character that opened it, and could not span lines. Every codebase of any age still carries the workarounds:
NL = "\n" # module-level constant for a newline
label = d["key"] # temp var, only to dodge quote reuse
text = f"{label}{NL}"
PEP 701 rewrote f-strings into the PEG grammar in 3.12. Inside {...} you are
now in ordinary Python:
-
Quote reuse.
f"{d["key"]}"is legal. So isf"{f"{inner}"}", to any nesting depth. -
Backslashes.
f"{"\n".join(parts)}"is legal. -
Multi-line expressions, in any f-string — not just triple-quoted ones —
and
#comments inside them. - Better errors. The tokenizer now points at the character that is wrong, not at the whole literal.
What did not change: an f-string still cannot be a docstring (it is not a
constant), and lambda and := still need parentheses inside a replacement
field, because a bare colon starts the format spec.
What you are building
def solve(rows: list[dict[str, object]], keys: list[str]) -> str
Render a fixed-column summary:
-
a header line — the
keys, joined with" | "; -
one line per row — for each key, the row’s value, joined with
" | "; a key the row does not have renders as-; -
a footer line —
"<n> row(s)".
The three parts are joined with newlines. With
rows=[{"name": "ada", "age": 36}] and keys=["name", "age"]:
name | age
ada | 36
1 row(s)
Write it as one f-string — same-quote subscripting for the lookups, a
"\n".join(...) inside a replacement field for the body, the expression
broken across lines for readability. That form is the point of the exercise;
the old workarounds produce identical output and teach nothing.
Note the distinction the tests care about: an absent key renders -, but a
key that is present with the value None renders None. dict.get with a
default cannot tell those apart on its own — reach for it deliberately.
The version wall
This is a syntax change. f"{d["key"]}" on 3.11 is a SyntaxError raised
at import time, before any code in the module runs. That means it cannot sit
behind if sys.version_info >= (3, 12):, cannot be feature-detected, and
cannot be shipped to a 3.11 user with a graceful fallback. The only defence is
requires-python = ">=3.12" in pyproject.toml, which is what makes the
installer refuse the wheel instead of the interpreter refusing the import.
Stuck?
Python reference solution
Sign in to attempt this problem and reveal the reference solution.