What’s new in Python 3.9?#

With Python 3.9, a new release cycle is used for the first time: in the future, new releases will appear annually (see also PEP 602). The developers hope that they will get faster feedback on new features.

With the first published release candidate, Python should also have a stable binary interface (application binary interface, ABI): there should no longer be any ABI changes in the 3.9 series, which means that extension modules no longer have to be recompiled for each version.

You can find more information in What’s New In Python 3.9.

In the following, I’ll give you a brief overview of some of the new features.

Installation#

Check#

[1]:
!python3 -V
Python 3.9.0rc1

or

[2]:
import sys
assert sys.version_info[:2] >= (3, 9)

PEP 584: Dictionary Merge and Update Operators#

Operators for the built-in dict class are now similar to those for concatenating lists: Merge (|) and Update (|=). This eliminates various disadvantages of the previous methods dict.update, {**d1, **d2} and collections.ChainMap.

Example ipykernel/ipykernel/kernelapp.py#

[ ]:
kernel_aliases = dict(base_aliases)
kernel_aliases.update({
    'ip' : 'IPKernelApp.ip',
    'hb' : 'IPKernelApp.hb_port',
    'shell' : 'IPKernelApp.shell_port',
    'iopub' : 'IPKernelApp.iopub_port',
    'stdin' : 'IPKernelApp.stdin_port',
    'control' : 'IPKernelApp.control_port',
    'f' : 'IPKernelApp.connection_file',
    'transport': 'IPKernelApp.transport',
})

kernel_flags = dict(base_flags)
kernel_flags.update({
    'no-stdout' : (
            {'IPKernelApp' : {'no_stdout' : True}},
            "redirect stdout to the null device"),
    'no-stderr' : (
            {'IPKernelApp' : {'no_stderr' : True}},
            "redirect stderr to the null device"),
    'pylab' : (
        {'IPKernelApp' : {'pylab' : 'auto'}},
        """Pre-load matplotlib and numpy for interactive use with
        the default matplotlib backend."""),
    'trio-loop' : (
        {'InteractiveShell' : {'trio_loop' : False}},
        'Enable Trio as main event loop.'
    ),
})

can be simplified with:

[ ]:
kernel_aliases = base_aliases | {
    'ip': 'KernelApp.ip',
    'hb': 'KernelApp.hb_port',
    'shell': 'KernelApp.shell_port',
    'iopub': 'KernelApp.iopub_port',
    'stdin': 'KernelApp.stdin_port',
    'parent': 'KernelApp.parent',
}}
if sys.platform.startswith ('win'):
    kernel_aliases ['interrupt'] = 'KernelApp.interrupt'

kernel_flags = base_flags | {
    'no-stdout': (
            {'KernelApp': {'no_stdout': True}},
            "stdout auf das Nullgerät umleiten"),
    'no-stderr': (
            {'KernelApp': {'no_stderr': True}},
            "stderr auf das Nullgerät umleiten"),
}}

Example matplotlib/legend.py#

[ ]:
hm = default_handler_map.copy()
hm.update(self._custom_handler_map)
return hm

can be simplified with:

[ ]:
return default_handler_map | self._handler_map

PEP 616: removeprefix() and removesuffix() for string methods#

With str.removeprefix(prefix) and str.removesuffix(suffix) you can easily remove prefixes and suffixes. Similar methods have also been added for bytes, bytearray objects, and collections.UserString. All in all, this should lead to less fragile, better performing and more readable code.

Example find_recursionlimit.py#

[ ]:
if test_func_name.startswith("test_"):
    print(test_func_name[5:])
else:http://localhost:8888/notebooks/docs/workspace/jupyter/kernels/python39.ipynb#Beispiel-find_recursionlimit.py
    print(test_func_name)

can be simplified with:

[ ]:
print (test_func_name.removeprefix ("test_"))

Example deccheck.py#

[ ]:
if funcname.startswith("context."):
    self.funcname = funcname.replace("context.", "")
    self.contextfunc = True
else:
    self.funcname = funcname

can be simplified with:

[ ]:
self.contextfunc = funcname.startswith ("context.")
self.funcname = funcname.removeprefix ("context.")

PEP 585: Additional generic types#

In Type Annotations, for example list or dict can be used directly as generic types – they no longer have to be imported separately from typing. Importing typing is thus deprecated.

Example#

[ ]:
def greet_all(names: list[str]) -> None:
    for name in names:
        print("Hello", name)

PEP 617: New PEG parser#

Python 3.9 now uses a PEG (Parsing Expression Grammar) parser instead of the previous LL parser. This has i.a. the following advantages:

The new parser is therefore more flexible and should be used primarily when designing new language functions. The ast module is already using the new parser without the output having changed.

In Python 3.10, the old parser and all functions that depend on it – mainly the obsolete parser module - are deleted. Only in Python 3.9 you can return to the LL parser on the command line with -X oldparser or with the environment variable PYTHONOLDPARSER=1.

PEP 615: Support for the IANA Time Zone Database in the Standard Library#

The new zoneinfo brings support for the IANA time zone database to the standard library.

[5]:
from zoneinfo import ZoneInfo
from datetime import datetime, timedelta

Pacific Daylight Time:

[6]:
dt = datetime(2020, 10, 31, 12, tzinfo=ZoneInfo("America/Los_Angeles"))
print(dt)
2020-10-31 12:00:00-07:00
[7]:
dt.tzname()
[7]:
'PDT'

Pacific Standard Time:

[8]:
dt += timedelta(days=7)
print(dt)
2020-11-07 12:00:00-08:00
[9]:
print(dt.tzname())
PST