5 New Python 3.10 Features You Should Know About

Conan Mercer Site Reliability Engineer

5 New Python 3.10 Features You Should Know About

29 Apr 2022 - Conan Mercer

This article explains the new features in Python 3.10, compared to 3.9. When Python releases a new version, a lot of the ideas originate from Python Enhancement Proposals (PEP).

These PEPs define in detail what has changed, in this article I have picked 5 of the most interesting proposals.

1. Structural Pattern Matching

If you have ever worked with C# or Java you may be familiar with "switch case" statements. Trying to do this in Python would have previously involved some cumbersome "if, elif, else" statements

New to Python 3.10 is structural pattern matching AKA the "switch, case" statement which has the following syntax:


def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 401:
            return "Unauthorized"
        case 403:
            return "Forbidden"
        case 404:
            return "Not found"
        case _:
            return "Something else"
Notice the final block "case _", the underscore works like a wildcard and will never fail to match. Interestingly, it is possible to combine multiple cases into a single pattern using the pipe operator "|":

case 401|403|404:
            return "Not happening"

2. Improved Error Messages

Python could be accused of misleading or unclear error reporting. To combat this, Python 3.10 introduces precise line numbers for debugging through PEP 626.
Before Python 3.10, syntax errors would often be reported in a somewhat vague fashion:

File "test.py", line 1
    expected = {'First': 1, 'Second':2

SyntaxError: unexpected EOF while parsing
Not anymore, version 3.10 introduces more precise information while parsing code. For example, if a bracket is never closed, the error message will be explicit and point to the line of code, and state the error in prose:

File "test.py", line 1
    expected = {'First': 1, 'Second':2
               ^
SyntaxError: '{' was never closed

3. A New Union Type Operator

Previously, when adding type hints with two types, the Union keyword was necessary:

def example_function(flexible_parameter: Union[float, string]) -> Union[float, string]:
	  return flexible_parameter
PEP 604 introduces writing Union types as X | Y instead of Union[X, Y]:

def example_function(flexible_parameter: float | string) -> float | string:
	  return flexible_parameter
This syntax, in my opinion, is more readable and gets the job done in less code.

4. Explicit Type Aliases

Take the example of representing speed using a tuple of average and maximum floats, and a group of cars by a list of such speed tuples. A group of speeds is then type hinted as list[tuple[float, float]]
To simplify type annotation, you define type aliases as follows:

Speed = tuple[float, float]
Car = list[Speed]
This approach can work, but often the type checker can not distinguish between a definition of a global variable or a type alias. To lend a hand to the type checker, type aliases can now be explicitly annotated:

from typing import TypeAlias

Speed: TypeAlias = tuple[float, float]
Car: TypeAlias = list[Speed]
The TypeAlias annotation makes the intention concrete, both to a type checker and to anyone reading the code.

5. Optional Length-Checking To zip

When combining multiple lists in Python, the built-in zip function is useful. However before Python 3.10 there was no check that all sequences being zipped had the same length. PEP 618 adds the optional strict boolean keyword parameter.

When enabled, a ValueError is raised if one of the arguments is exhausted before the others. For example, the code below would raise a ValueError, because the strict parameter is set to True.


z = zip([8.0, 12.0, 16.0], [8, 12, 20, 32], strict=True)
Here is a list of all of the PEP features introduced into Python 3.10