Skip to content

New Syntax and Features#

Python 3.10 through 3.13 added syntax and stdlib features that change how production code is written: structural pattern matching, modern union types, exception groups, improved error messages, type parameter syntax, and experimental free-threading. This page focuses on practical, interview-relevant additions for Python 3.10+.

How to use this page

Target Python 3.11+ for the best balance of features and support. Cross-reference Type Hints and Annotations for typing features and Global Interpreter Lock for free-threading internals.

At a glance
Track Python Advanced → New Python Features and Enhancements
Sections 16 major topics
Outline Use the right-hand TOC to jump

Topics: Version feature matrix · Structural pattern matching (3.10+) · Union types with | (3.10+) · Parenthesized context managers (3.10+) · dataclass improvements · Exception groups and except* (3.11+) · Self type (3.11+) · tomllib — read TOML from stdlib (3.11+) · … (+8 more)

  1. Version feature matrix
  2. Structural pattern matching (3.10+)
  3. Union types with | (3.10+)
  4. Parenthesized context managers (3.10+)
  5. dataclass improvements
  6. Exception groups and except* (3.11+)
  7. Self type (3.11+)
  8. tomllib — read TOML from stdlib (3.11+)
  9. Improved error messages (3.11+)
  10. Type parameter syntax (3.12+)
  11. typing.override (3.12+)
  12. Walrus operator := (3.8+, still essential) … and 4 more sections

Version feature matrix#

Feature Version PEP
match / case 3.10 634
X \| Y union types 3.10 604
dataclass(kw_only=True) 3.10
Exception groups / except* 3.11 654
Self type 3.11 673
tomllib (stdlib TOML) 3.11 680
Fine-grained error locations 3.11 657, 678
typing.override 3.12 698
Type parameter syntax class C[T] 3.12 695
Improved f-string parsing 3.12 701
Per-interpreter GIL (optional) 3.12 684
Free-threaded build (--disable-gil) 3.13 703
Experimental JIT 3.13 744
Improved interactive REPL 3.13

Structural pattern matching (3.10+)#

from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int

def describe(value) -> str:
    match value:
        case 0:
            return "zero"
        case [x, y]:
            return f"pair: {x}, {y}"
        case {"type": "user", "name": str(name)}:
            return f"user {name}"
        case Point(x=0, y=y):
            return f"on y-axis at {y}"
        case Point(x, y) if x == y:
            return f"diagonal at {x}"
        case _:
            return "unknown"
Pattern Matches
Literals case 42:, case "ok":
Capture case x: binds x
Sequence case [a, b]: length 2 list
Mapping case {"key": val}: key present
Class case Point(x, y): destructuring
Guard case x if x > 0:
Wildcard case _: default

Use match for structured data

Excellent for AST nodes, JSON shapes, and command dispatch — clearer than long if/elif chains.

OR patterns and aliases#

match status:
    case 200 | 201 | 204:
        return "success"
    case code if 400 <= code < 500:
        return "client error"

Union types with | (3.10+)#

def normalize(value: str | int | None) -> str:
    if value is None:
        return ""
    return str(value)

Replaces Union[str, int, None] from typing — preferred in modern codebases. See Type Hints and Annotations.


Parenthesized context managers (3.10+)#

from contextlib import contextmanager

@contextmanager
def tag(name: str):
    print(f"[{name}] start")
    yield
    print(f"[{name}] end")

with (
    tag("a"),
    tag("b"),
):
    print("work")

Cleaner than nested with blocks for multiple managers.


dataclass improvements#

from dataclasses import dataclass, field

@dataclass(kw_only=True, slots=True, frozen=True)
class Config:
    host: str = "localhost"
    port: int = 8080
    tags: list[str] = field(default_factory=list)
Flag Version Effect
kw_only=True 3.10 All fields keyword-only
slots=True 3.10 __slots__, lower memory
frozen=True 3.7+ Immutable instances

Exception groups and except* (3.11+)#

def run_tasks():
    raise ExceptionGroup(
        "task failures",
        [
            ValueError("bad input"),
            TypeError("wrong type"),
        ],
    )

try:
    run_tasks()
except* ValueError as eg:
    for exc in eg.exceptions:
        print("value error:", exc)
except* TypeError as eg:
    print("type errors:", len(eg.exceptions))
Concept Detail
ExceptionGroup Bundles multiple exceptions from parallel tasks
except* Handles matching sub-exceptions, re-raises rest
BaseExceptionGroup Includes KeyboardInterrupt, etc.

Relevant for asyncio.TaskGroup and structured concurrency.


Self type (3.11+)#

from typing import Self

class Builder:
    def reset(self) -> Self:
        self._state = {}
        return self

    def with_name(self, name: str) -> Self:
        self._state["name"] = name
        return self

Subclass return types stay correct without quotes or TypeVar boilerplate.


tomllib — read TOML from stdlib (3.11+)#

import tomllib
from pathlib import Path

config = tomllib.loads(Path("pyproject.toml").read_bytes())
# or tomllib.load(binary_file) — must be binary mode
Module Direction Version
tomllib Read 3.11+ stdlib
tomli Read Backport for < 3.11
tomli-w Write Third-party

Improved error messages (3.11+)#

Python 3.11+ pinpoints error locations in expressions:

# SyntaxError points to the exact position in multi-line expressions
# TypeError suggestions: "Did you mean 'append'?"

3.12 adds more friendly NameError hints and f-string error locations (PEP 701 — f-strings can contain any expression including quotes).

PEP 701 f-strings (3.12+)#

# Previously illegal — now valid
items = ["a", "b"]
print(f"{'|'.join(items)}")

Type parameter syntax (3.12+)#

class Stack[T]:
    def __init__(self) -> None:
        self._items: list[T] = []

    def push(self, item: T) -> None:
        self._items.append(item)

    def pop(self) -> T:
        return self._items.pop()

def first[T](items: list[T]) -> T:
    return items[0]

PEP 695 replaces many TypeVar + Generic patterns. Classic syntax still works — see Type Hints and Annotations.

type statement (3.12+)#

type Point = tuple[float, float]
type UserId = int

typing.override (3.12+)#

from typing import override

class Base:
    def save(self) -> None: ...

class Derived(Base):
    @override
    def save(self) -> None:
        ...

Static checkers error if the parent method does not exist — catches rename typos.


Walrus operator := (3.8+, still essential)#

# Read in [File Handling](../../Python%20Intermediate/File%20Handling.md) patterns
if (n := len(data)) > 10:
    print(f"large: {n}")

while (line := f.readline()):
    process(line)

Assign and test in one expression — reduces duplication.


zoneinfo — IANA time zones (3.9+, common in modern code)#

from zoneinfo import ZoneInfo
from datetime import datetime

dt = datetime(2025, 7, 7, 12, 0, tzinfo=ZoneInfo("Asia/Kolkata"))

Prefer over pytz for new projects.


Python 3.13 highlights#

Free-threaded CPython (experimental)#

import sys
if hasattr(sys, "_is_gil_enabled"):
    print("GIL enabled:", sys._is_gil_enabled())

Optional python3.13t build — see Global Interpreter Lock.

Experimental JIT#

Enabled with PYTHON_JIT=1 in some builds — copy-and-patch JIT, performance varies by workload. Not a replacement for algorithmic improvements.

Improved REPL#

Multiline editing, color, better history — affects developer experience, not deployment semantics.

copy.replace() for dataclasses (3.13)#

from dataclasses import dataclass, replace  # replace since 3.7
# 3.13 adds copy.replace on some immutable types in broader stdlib push

Use dataclasses.replace for immutable config updates:

@dataclass(frozen=True)
class Settings:
    debug: bool = False

prod = replace(Settings(), debug=False)

Deprecated / removed awareness#

Item Status
distutils Removed 3.12 — use setuptools / packaging
imp Removed 3.12 — use importlib
typing.TypedDict functional form Prefer class syntax
Old % string formatting Still works — f-strings preferred

Check Modules and Packages for modern packaging.


Choosing a minimum version#

Target Rationale
3.10 match, \| unions, kw_only dataclasses
3.11 Exception groups, Self, faster CPython
3.12 Type params, override, better errors
3.13 Free-threading experiments, JIT trials

Document requires-python = ">=3.11" in pyproject.toml for new libraries.


Interview traps (quick reference)#

Trap What goes wrong Safe approach
match is switch from C No fall-through; different semantics Learn pattern forms
case [x, y] matches any 2-list Also matches strings (sequences!) Know sequence patterns
except* vs except Different re-raise behavior Use except* only with groups
tomllib.load text mode TypeError — needs bytes read_bytes() or "rb"
X \| Y at runtime without from __future__ Syntax error in 3.9 Require 3.10+
Free-threading is default in 3.13 Still optional separate build Check sys._is_gil_enabled()
PEP 695 requires runtime 3.12 Syntax error on older interpreters Match requires-python

Mental model checklist#

  1. What patterns can match/case destructure?
  2. When do you use except* instead of except?
  3. What is the difference between Union[X, Y] and X | Y?
  4. Why must tomllib read binary files?
  5. What does typing.override catch at check time?
  6. What is the free-threaded build in 3.13?

What's next#

Topic Page
Full typing guide Type Hints and Annotations
GIL / free-threading Global Interpreter Lock
Error handling Error Handling
Packaging Modules and Packages