What's New in Python 3.10¶
3.10
Python 3.10 was released in October 2021. It's the release that brought structural pattern matching — the most significant new syntax addition since walrus operators in 3.8. It also delivered dramatically better error messages.
Summary¶
| Category | Change |
|---|---|
| Language | Structural pattern matching (match/case) — PEP 634 |
| Language | Parenthesized context managers |
| Language | Better isinstance() with union types |
| Error Messages | Much clearer SyntaxError, IndentationError messages |
| Typing | X | Y union type syntax (PEP 604) |
| Typing | TypeAlias, ParamSpec, TypeGuard |
| Standard Library | zip(..., strict=True) |
Structural Pattern Matching — PEP 634¶
This is Python's version of what other languages call switch/match, but much more powerful. You match not just values but structures.
command = input("Enter command: ")
match command.split():
case ["quit"]:
print("Quitting.")
case ["go", direction]:
print(f"Going {direction}.")
case ["go", direction, speed]:
print(f"Going {direction} at {speed} speed.")
case ["pick", "up", item]:
print(f"Picked up {item}.")
case _:
print(f"Unknown command: {command!r}")
You can match on class instances too:
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
def describe(point: Point) -> str:
match point:
case Point(x=0, y=0):
return "origin"
case Point(x=0, y=y):
return f"on y-axis at {y}"
case Point(x=x, y=0):
return f"on x-axis at {x}"
case Point(x=x, y=y):
return f"at ({x}, {y})"
See the full Pattern Matching guide for all pattern types: literal, capture, wildcard, OR, AS, guard, sequence, mapping, and class patterns.
Union Types with | — PEP 604¶
Previously you had to write Union[int, str] from typing. Now you can use | directly:
# Old way
from typing import Union, Optional
def process(value: Union[int, str]) -> Optional[str]:
...
# New in 3.10
def process(value: int | str) -> str | None:
...
This also works with isinstance() and issubclass():
isinstance(42, int | str) # True
isinstance("hello", int | str) # True
isinstance(3.14, int | str) # False
Parenthesized Context Managers¶
Multi-line with statements are now legal with parentheses:
# Old — need backslash continuation
with open("a.txt") as a, \
open("b.txt") as b:
...
# New in 3.10 — clean parentheses
with (
open("a.txt") as a,
open("b.txt") as b,
open("c.txt") as c,
):
...
Better Error Messages¶
3.10 introduced a big improvement in SyntaxError and IndentationError messages. Examples:
# Forgetting closing bracket
my_list = [1, 2, 3
^
SyntaxError: '[' was never closed
# Common dictionary mistake
d = {"key": "value" "oops": 1}
^^^^^^
SyntaxError: invalid syntax. Perhaps you forgot a comma?
zip(..., strict=True)¶
Catches a common bug: zipping iterables of different lengths silently truncates to the shortest. With strict=True, it raises ValueError instead: