# New Features In Python 3.10 You Should Know

This article shows and explains the most important new features in Python 3.10. The release is expected to be on 2021-10-04 (see [Python 3.10 Release Schedule](https://www.python.org/dev/peps/pep-0619/)).

%[https://youtu.be/brq_Nvu2iDc]

## Overview
Before we dive into the details, here's a brief summary of the most important changes:

* Structural Pattern Matching (New syntax feature)
* Parenthesized context managers (New syntax feature)
* New optional `strict` argument for `zip()` to ensure same length
* Better error messages and interpreter improvements
* Allow writing union types as X | Y (New *typing* feature)
* Explicit Type Aliases  (New *typing* feature)
* Require OpenSSL 1.1.1 or newer
* Deprecate distutils module
* Constructors  `str()`, `bytes()`, and `bytearray()` are now faster
* Faster python startup time through fewer imports

## Structural Pattern Matching

Structural Pattern Matching lets you match variables against a set of different possible values (like the *switch/case* in other languages). But it also allows to match against patterns of values, e.g., an object with a certain property set to a specific value. 

Structural pattern matching has been added in the form of a `match` statement and `case` statements of patterns with associated actions.

Syntax:
```
match subject:
    case <pattern_1>:
        <action_1>
    case <pattern_2>:
        <action_2>
    case _:
        <action_wildcard>
```

Example:
```python
def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 401 | 403:
            return "Not allowed"
        case 404:
            return "Not found"
          case 418:
            return "I'm a teapot"
        case _:
            return "Something's wrong with the internet"
```

Notice how you can combine several literals in a single pattern using `|` ("or").

Without the use of `_` in a case statement, a match may not exist. If no match exists, the behavior is a no-op. For example, if status of 500 is passed, and `_` is not used, the result is None.

In addition, a variable can also be matched against patterns. Patterns can look like unpacking assignments, and a pattern may be used to bind variables:

```python
# point is an (x, y) tuple
match point:
    case (0, 0):
        print("Origin")
    case (0, y):
        print(f"x=0 y={y}")
    case (x, 0):
        print(f"y={x} y=0")
    case (x, y):
        print(f"x={x}, y={y}")
    case _:
        raise ValueError("Not a point")
```

There are more syntax options available for the pattern matching feature, such as using an additional if statement as guard, or matching for class patterns. A more detailed documentation is available [here](https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching).

## Parenthesized context managers

Using enclosing parentheses for continuation across multiple lines in context managers is now supported. This allows formatting a long collection of context managers in multiple lines:

```python
with (
    CtxManager1() as ctx1,
    CtxManager2() as ctx2
):
    # do something
```

## Optional length-checking to `zip()`

An optional `strict` boolean keyword parameter to the built-in [zip()](https://docs.python.org/3/library/functions.html#zip) method was added. When set to True, a *ValueError* is raised if one of the arguments is exhausted before the others:

```python
names = ['Max', 'Mary', 'Ben']
ages = [22, 26]

result = zip(names, ages)
print(list(result))
# [('Max', 22), ('Mary', 26)]
# --> By default the zipped elements simply stop when the end
#     of the shorter iterable is reached

result = zip(names, ages, strict=True)

# Error!
Traceback (most recent call last):
  File "example.py", line 4, in <module>
    print(list(result))
ValueError: zip() argument 2 is shorter than argument 1
```

## Better Error messages and Interpreter improvements

Many of the errors messages have been improved — not only delivering more precise information about the error, but also more precise information about where the error actually occurs.

Look at this simple example with a missing parenthesis:
```python
print("Hello"
print("World")
```

Here’s the Python 3.9 Error. It does not give you a clue at all why and where the error happens:
```
  File "example.py", line 2
    print("World")
        ^
SyntaxError: invalid syntax
```

And this is the Python 3.10 Error. You can see the issue immediately:
```
  File "example.py", line 1
    print("Hello"
         ^
SyntaxError: '(' was never closed
```

Here are some other examples with an improved error message.

* Missing `:` before blocks: *"SyntaxError: expected ':'"*
* Missing parenthesis: *"SyntaxError: did you forget parentheses around the comprehension target?"*
* Missing commas: *"SyntaxError: invalid syntax. Perhaps you forgot a comma?"*

Notice how nicely the Python interpreter asks ;)

Furthermore, many *IndentationError* exceptions now have more context regarding what kind of block was expecting an indentation, including the location of the statement:
```python
def foo():
    if lel:
    x = 2

File "<stdin>", line 3
    x = 2
    ^
IndentationError: expected an indented block after 'if' statement in line 2
```

More examples of the new error messages can be found [here](https://docs.python.org/3.10/whatsnew/3.10.html#better-error-messages).

In addition to improved Error messages, more precise and reliable line numbers for debugging, profiling and coverage tools are available. Tracing events with the correct line number are generated for all lines of code executed and only for lines of code that are executed.

## New typing features

This section covers major changes affecting type hints and the [typing](https://docs.python.org/3/library/typing.html) module.

### Allow writing union types as X | Y

A new type union operator was introduced which enables the syntax `X | Y`. This provides a cleaner way of expressing "either type X or type Y" instead of using [typing.Union](https://docs.python.org/3.10/library/typing.html#typing.Union):

```python
# old syntax
from typing import Union
def square(number: Union[int, float]) -> Union[int, float]:
    return number ** 2

# new syntax
def square(number: int | float) -> int | float:
    return number ** 2
```

Additionally, this new syntax is also accepted as the second argument to `isinstance()` and `issubclass()`:
```python
isinstance(1, int | str)
```

### Explicit Type Aliases

Now the typing module has a special value [TypeAlias](https://docs.python.org/3.10/library/typing.html#typing.TypeAlias) which lets you declare type aliases more explicitly. This is useful for type checkers to distinguish between type aliases and ordinary assignments:
```python
from typing import TypeAlias
StrCache: TypeAlias = 'Cache[str]'
```

### Parameter Specification Variables

In addition, two new options to improve the information provided to static type checkers have been provided with [typing.ParamSpec](https://docs.python.org/3.10/library/typing.html#typing.ParamSpec) and [typing.Concatenate](https://docs.python.org/3.10/library/typing.html#typing.Concatenate).

## Important updates and deprecations

### Require OpenSSL 1.1.1 or newer

Python now requires OpenSSL 1.1.1 or newer. OpenSSL 1.0.2 is no longer supported.
This affects the `hashlib`, `hmac`, and `ssl` module and modernizes one of CPython’s key dependencies.

### Deprecate distutils module.

The entire distutils package is deprecated, to be removed in Python 3.12. Its functionality for specifying package builds has already been completely replaced by third-party packages setuptools and packaging, and most other commonly used APIs are available elsewhere in the standard library.

## No new modules, but many improved ones
No new modules are added, but a lot of modules have been improved. Among them are:

*asyncio, argparse, base64, contextlib, dataclasses, hashlib, os, pathlib, pprint, statistics, socket, ssl, sqlite3, threading, traceback, typing, unittest*, and *xml*. 

For the full list of improved modules see [here](https://docs.python.org/3.10/whatsnew/3.10.html#improved-modules).

## Optimizations
Multiple optimizations were implemented (see [full list](https://docs.python.org/3.10/whatsnew/3.10.html#improved-modules)). The most important ones are:

* Constructors  `str()`, `bytes()`, and `bytearray()` are now faster (around 30–40% for small objects)
* The  runpy module now imports fewer modules. The `python3 -m module-name` command startup time is 1.4x faster in average. On Linux, `python3 -I -m module-name` imports 69 modules on Python 3.9, whereas it only imports 51 modules (-18) on Python 3.10.

## Closing thoughts
Python 3.10 brings many great new features, improvements, and optimizations. The most interesting one is certainly the pattern matching feature, which can be useful in various scenarios.

The new error messages are also a great improvement and can save a lot of time when trying to find the mistake. This could be especially helpful for beginners that previously often times only got confused by the error message.

If you like this article, make sure to share it on Twitter and let me know which new feature you like the most :)

## Resources
The official article with all new features can be found here:   
[https://docs.python.org/3.10/whatsnew/3.10.html](https://docs.python.org/3.10/whatsnew/3.10.html)

