Python 3.10 Digest

New features for Python 3.10 is now on beta, this means that no new features will be added for this version.

Let’s take a look to the most important features this version will onboard.

Structural Pattern Matching

This one is a big one, evaluating objects can be tedious and not pretty. This is where Structural Pattern comes into play.

Before, we had to write stuff like:

if 'key' in my_map:
do_stuff
elif 'value' == my_map['this_key']:
do_stuff
elif my_map['code'] in [400,403]:
do_stuff
else:
do_other_stuff

Now, we can relay on Structural Patterns:

match status:
case 401 | 403:
return 'Unauthorized'
case 200:
return 'OK'
case _:
return 'Unexpected

Note that case _: if the default for this syntax, also unlike in C/C++ with switch/case when you meet the next case statement, the execution will got outside of the match statement.

This is the structural part, now the pattern part:

match status:
case {"status": 'error', "err_code": err, **rest}:
return f"Error:{err} : {rest}"
case {"status": 'success', **rest}:
return f"Success: {rest}"
case _:
return "Unexpected"

On this example, if status have 'status' == 'error' and an 'err_code' key, it will fall to the first case. When 'status' == 'success' it falls to the second case.

Whenever status isn’t in any of the previous case (note that this include status is an object with no get() method) it will fall on the default case.

Note that we can assign a variable to parts of the expression we are evaluating. This is basically syntax sugar, but that will allow a nice code readability. I’m really impatient to be able to use this new functionality in AWS Lambda development.

The code I showed uses int of dict, but this feature can be used with many other types, and this is just a quick overview of what can be achieved.

Type Unions

Until now, to specify that a parameter can be any of multiple types to the typing hints, we had to import typing.Union and use a syntax like

def my_function(param: typing.Union[int, str]):
pass

To achieve the exact same thing, python 3.10 allows:

def my_function(param: int | str):
pass

This syntax offers 2 massive advantages:

  • It’s easier to read
  • It avoid importing typing.Union, this mean cleaner import statements

Type Alias

This feature, will allow to prevent using my_var = 'MyType' as placeholder for a type that is not yet declared. Instead now it’s possible to use my_var: TypeAlias = 'MyType'. The difference is quite minimal, but this allows to know the string is a placeholder and not a literal string.

Type Guards

To avoid type errors, it’s common to have the necessity of testing the type deeper than a simple use of isinstance(), like checking if all element of a list had the same type, or if a map has certain elements.

Type guards are typing int to check this. It’s used like this:

def is_str_list(val: List[Object] -> TypeGuard[List[str]]:
return all(isinstance(x, str) for x in val)

This function will check if all elements of a list are strings, using TypeGuard instead of bool, will allow us to directly know what type check is done by the function.

TypeGuard is in typing library