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.