Python 3.8 will/has reached its end of life by the end of this month. Soon, you will be forced to upgrade as tools and libraries gradually start removing its support. If you are considering upgrading to the latest Python version, take it. But especially library maintainers don’t have that luxury and still have to keep 3.9 support around. It’s been a while since all the „What’s new in Python 3.9″ articles came out. So here’s a farewell of what’s going away and hello to what you can use instead.
Before we go into the details of what’s changing, I recommend trying a pyupgrade tool first to see what Python 3.9+ changes can be done for you automatically.

typing Generic (PEP 585)
While typing generics such as list […] and dict […, …] have been possible since Python 3.7 thanks to from __future__ import annotations, there might be still places in the code base that use the old typing. List / typing. Dict generics. After Python 3.8, these can officially go. What can be replaced?
typing. Tuple -> tupletyping. List -> listtyping. Dict -> dicttyping. Set -> settyping. FrozenSet -> frozensettyping. Type -> typetyping. ContextManager -> contextlib. AbstractContextManagertyping. AsyncContextManager -> contextlib. AbstractAsyncContextManagertyping. Pattern -> re. Patterntyping. Match -> re. Match
There are also other generics that are completely new.
Operator for merging dicts (PEP 884)
{**d1, **d2} -> d1 – d2
d1. update(d2) -> d1 |= d2
New String Methods to Remove Prefixes and Suffixes (PEP 616)
You may have various local or back-ported implementations that can now be replaced with built-in ones:
removeprefix(string, prefix) -> string.removeprefix(prefix)
removesuffix(string, prefix) -> string.removesuffix(prefix)
