Python 3.10 (original) (raw)

Python 3.10 is out (and has been for a while, I’m late posting this), with new features and changes. The big new language feature this update is pattern matching. We get much better errors, the always-present typing improvements, and finally some real usage of the new PEG parser from 3.9.



Official release image

Better Errors

This is the main reason you should be using 3.10+ to run your code, even if you still support older versions. Better error messages makes debugging code easier automatically, without needing libraries to start using some new feature!

Some key improvements are:

In addition to this, CPython now provides more precise line numbers for debuggers and other tools.

Pattern Matching

This is a huge feature and the first new block type since with blocks (2.6). It is also the first nested block type in Python. It’s a huge new feature, so let’s just look at a small example:

# Load pyproject using tomli (or tomllib in Python 3.11)

match pyproject:
    case {"tool": {"mypy": {"strict": value}}}:
        print(f"You have strict mode set to {value}, congrats!")
    case _:
        print("Ahh, buggers. No strict mode for you.")

This may look a bit like a switch statement (and that’s a subset), but it also has several other features, some of which you see above. First, it can match against structure, such as collections and mappings; this can be nested as well. Second, while it can compare values by equality, it can also bind variables (value above) wherever they occur in the structure. Third, it matches top to bottom (and only one), so you can add a final case _ if you want.

A few features not listed above include the ability to add guards (final if statements), match a union of several things (denoted with |), and capture a portion explicitly with as. One more feature should be mentioned explicitly: support for classes, which can replace isinstance. match x: case Thing(): is identical to isinstance(x, Thing). You can also match on attributes withattribute= keyword-like syntax and positionally if the class supports it.

Read more in thewhat’s new pageor in PEP 636, which is a tutorial PEP.

Typing improvements

As always, most of these improvements can either be imported fromtyping_extensions or can be used in 3.7+ withfrom __future__ import annotations as long as you are not using them at runtime.

Type Unions

The biggest feature for typing is the native support for the union operator. You can now spell Union[int, str] as int | str, and Optional[str] asstr | None. This really improves readability and removes many of the imports needed to specify types (especially combined with 3.9’s stdlib generics). As a bonus, this new union is usable at runtime in isinstance in 3.10+.

Other

A new system was developed to allow libraries to add parameters to a callable (think decorators like pytest and nox provide).

A function can now be a type guard - a function that returns a boolean that is tied to the types it sees. So you could write a function like is_int and the typing system will know that the argument is an int if the function returns True.

You can use TypeAlias to specify that a string is really a type alias and not just a string.

Other improvements

Parenthesized context managers

Due to the new PEG parser, you can now officially add parenthesis around context managers. This is now the nicest way to apply several at a time:

with (
    A() as a,
    B(),
    C() as c,
):
    ...

This was technically supported in CPython 3.9 if you were using the new parser (the default). In 3.10, the old parser has been removed.

Strict zip

zip now has a strict flag that you can set; this was hard to do efficiently on arbitrary iterators any other way, and usually strict=True is what you want. For example:

nums = [1, 2, 3]
lets = "ABC"

for num, let in zip(nums, lets, strict=True):
    print(f"{num}: {let}")

If you add or remove to either or the two lists without changing the other,zip will now throw an error rather than just matching the shortest list. Doing this correctly (without iterating over the input twice) was tricky before 3.10.

Minor features

There were also various changes related to current and future speedups. Functions now cache __globals__['__builtins__'] into .__builtins__, which sounds useful for monkeypatching in tests.

Stdlib improvements

Dataclasses

Dataclasses received a few really huge improvements in 3.10, making them more like the attrs library than ever.

The slots=True option was added, which will generate __slots__ (and recreate the class, if that matters to you).

You can also now set keyword only fields - either on the entire class or a specific field (with kw_only=True), or by defining a special _: KW_ONLYfield that will make subsequent fields keyword only. Besides readability and future-proofing against rearranging attribute order, this also allows subclasses to set defaults on attributes in a parent class! In general, mixing subclassing and defaults is much easier with keyword-only support. For example:

@dataclasses.dataclass(kw_only=True)
class Record:
    kind: str
    name: str
    id: int


@dataclasses.dataclass(kw_only=True)
class Movie(Record):
    kind: str = "movie"

Minor features

Deprecations, warnings, and removals

Some of the Python 2 compatibility removals that were delayed from 3.9 were delayed one more release (3.11). There still are a nice set of new deprecations and warnings, though! This includes a lot of the old module loading API. Thecollections.* aliases to collections.abc.* have been removed.

There’s a new opt-in warning (-X warn_default_encoding) if you forget to specify the encoding when using open. In most cases, you wantencoding="utf-8", rather than the default (which is now possible to specify using "locale"). Python 3.15 will change the default to be "utf-8", so you should always specify this when using open in text mode to be forward compatible. And you can now force Python to use utf-8 by default withPYTHONUTF8 envvar or -X utf8 on the command line.

Distutils is officially deprecated, slated for removal in 3.12.

Final words

Python 3.10 is a solid release, with solid improvements to errors and typing, and a fun new feature (pattern matching) to play with. It’s already powering Pyodide, a WebAssembly version of Python for your browser with compiled extension support.

Sources and resources