Free Python reference · JavaScript timeline
Python 3.12: Cleaner generics and fewer f-string restrictions
Type parameters and type aliases gain dedicated syntax; f-strings accept more ordinary Python expressions.
Released · Editorial review October 25, 2026
Introduced in Python 3.12 · Typing
Type parameters and type aliases
Declare a generic parameter beside the function name with def first[T](...). That parameter connects the input element type to the result type for static checking. The type statement gives an alias a distinct declaration and can introduce its own parameters.
Earlier code commonly declared a separate TypeVar and assigned an alias to a name. The newer syntax keeps the parameter close to the definition that uses it. It still does not enforce element types during ordinary execution.
The example annotates a small score table and returns its first score. Its input is nonempty; if you need an empty-input behavior, design that contract rather than expecting the type parameter to supply one.
Earlier approach
from typing import TypeVar T = TypeVar("T") def first(items: list[T]) -> T: return items[0]
Context fragment; read it with the example below.
Worked example
Minimum Python 3.12
type ScoreTable = dict[str, list[int]] def first[T](items: list[T]) -> T: return items[0] scores: ScoreTable = {"Ada": [8, 9]} print(first(scores["Ada"]))
Expected output
8
Example checked with CPython 3.14.8, CPython 3.15.0, Pyodide Python 3.13.2.
Common mistake
The type statement creates a type alias, not a class for validating records. Generic relationships need a supporting type checker to be checked statically.
Try it yourself
Call first with a list of strings. What return type should a type checker infer, and what happens for an empty list?
Read more: Python 3.12 release notes · PEP 695
Introduced in Python 3.12 · Syntax
F-strings accept more expression syntax
Python 3.12 integrates f-strings into the regular grammar and removes several earlier restrictions. You can reuse the outer quote style inside an expression, include backslashes in string literals inside expressions, and use multiline expressions with comments.
These changes help when formatting values selected from dictionaries or joining several lines. Compatibility still matters: a source file using the newer form will fail to parse on an older interpreter before any version-checking branch can run.
The example uses double quotes both for the f-string and the dictionary key. When supporting Python 3.11, alternate quote styles or compute the intermediate value first.
Worked example
Minimum Python 3.12
record = {"name": "Ada"} print(f"Learner: {record["name"]}") parts = ["one", "two"] print(f"Joined: {" / ".join(parts)}")
Expected output
Learner: Ada
Joined: one / two
Example checked with CPython 3.14.8, CPython 3.15.0, Pyodide Python 3.13.2.
Common mistake
More permissive grammar does not make a dense expression readable. Introduce a named intermediate value when the formatting becomes hard to scan.
Try it yourself
Rewrite the first example so it also parses on Python 3.11, without changing its output.
Read more: Python 3.12 release notes · PEP 701
Recap
Type parameters and type aliases gain dedicated syntax; f-strings accept more ordinary Python expressions. Prefer the clearest form that works on your project's supported Python versions.
Read the full Python 3.12 release notes →