typenil

Matt White

developer

typenil

developer

Python 3.9 Features I'm Excited to See

As of 2020-08-11, the first release candidate of Python 3.9 has been released - officially making it Christmas in August; let’s open presents.

Exciting

Vaguely ordered by ascending excitement.

Native Dict Unions

PEP 584: Add union operators to dict

At the moment, if you want to merge a couple of dicts, the primary methods are to use either {**first_dict, **second_dict} or first_dict.update(second_dict) (which modifies first_dict in-place):

a = {0: 0, 1: 0, 2: 0}
b = {1: 1, 2: 2, 3: 3}

self.assertEqual({**a, **b}, {0: 0, 1: 1, 2: 2, 3: 3})

# `b` is modified in-place
b.update(a) 

self.assertEqual(b, {0: 0, 1: 0, 2: 0, 3: 3})

The syntax introduced in Python 3.9 is a lot more straightforward, allowing you to merge dicts with a pipe, e.g. first_dict | second_dict or first_dict |= second_dict (which, again, modifies first_dict in-place).

The order of the dicts still matters, i.e. whichever dict comes last will take precedence when there are key collisions.

a = {0: 0, 1: 0, 2: 0}
b = {1: 1, 2: 2, 3: 3}

# `b` colliding keys `1` and `2` still take precedence over `a`
self.assertEqual(a | b, {0: 0, 1: 1, 2: 2, 3: 3})

# `b` is modified in-place
b |= a

# `a` colliding keys `1` and `2` still take precedence over `b`
self.assertEqual(b, {0: 0, 1: 0, 2: 0, 3: 3})

Native String (Pre|Suf)fix Removal

PEP 616: String methods to remove prefixes and suffixes

It’s hard to overstate how often I need to strip prefixes or suffixes - and doing it in Python has been pretty verbose up to now.

# Stripping a prefix
if some_str.startswith(some_prefix):
    some_str = some_str[len(some_prefix):]

# Stripping a suffix
if some_str.endswith(some_suffix):
    some_str = some_str[:-len(some_suffix)]

Yeah, you can collapse these to one liners, but it’s still ugly as hell - and God forbid you need to do both at the same time.

I’m thrilled that removeprefix and removesuffix are finally available in Python 3.9:

# Stripping a prefix
some_str = some_str.removeprefix(some_prefix)

# Stripping a suffix
some_str = some_str.removesuffix(some_suffix)

# What the hell? Let's do both!
some_str = some_str.removeprefix(some_prefix).removesuffix(some_suffix)

Standard Collection Type Annotations

PEP 585: Type hinting generics in standard collections

This is a feature I’ll be using every day. If you use type annotations to a serious extent, you’ll probably be familiar with some version of the following:

from typing import Dict, List, Set

str_dict: Dict[str, str] = {
   "only": "strings",
   "nothing": "else",
}

float_list: List[float] = [1.1, 2.2, 3.3]

int_set: Set[int] = {1, 2, 3}

To get the benefits of type checking, you either have to import from typing (like above) or import annotations from __future__.

It’s just an import, but it can add up in a large project - especially if you find yourself copying any type-annotated code from one file to another (or, say, from StackOverflow).

With 3.9, things will be a bit cleaner:

str_dict: dict[str, str] = {
   "only": "strings",
   "nothing": "else",
}

float_list: list[float] = [1.1, 2.2, 3.3]

int_set: set[int] = {1, 2, 3}

Honorable Mention

I’m not not excited.

Type Annotation.. Annotations?

PEP 593: Flexible function and variable annotations

As more Python libraries leverage type annotations, there’s value in giving a flexible way to add metadata alongside particular types. This PEP introduces the Annotated construct which takes a type and an arbitrary list of arguments that serve as metadata, e.g.

Annotated[float, ValueRange(42, 420)]
Annotated[int, IsDivisibleBy(4), IsAfraidOfSeven(False)]
Annotated[tuple, MinLen(1), MaxLen(7)]

To support these annotations, typing.get_type_hints is changing to provide an include_extras kwarg (defaulting to False for backwards compatibility) that indicates whether to return this additional metadata.

I see how this could be a pretty useful PEP for libraries, but I don’t see a use for it in my own work, yet.

Good to Know

Not throwing shade or anything. Just don’t see these changing my life very much.

PEP 615: Support for the IANA time zone database in the standard library

This is a PEP that I need to spend more time with to really understand. My ridiculously dumbed-down (due to me, not you) summary is that it introduces a new zoneinfo API that replaces a lot of the functionality that you’d normally want to use pytz for, e.g.

from zoneinfo import ZoneInfo
from datetime import datetime

zone = ZoneInfo("America/Denver")
dt = datetime(2020, 12, 9, 6, tzinfo=zone)

PEP 692: Annual release cycle for Python

Python releases once a year now.

PEP 617: New PEG parser for CPython

Probably only relevant if you work on CPython or have an interest in compilers.

Join me in becoming a little less terrible every day.