How Python 3.9 fixed decorators and improved dictionaries | Opensource.com

How Python 3.9 fixed decorators and improved dictionaries

Explore some of the useful features of the recent version of Python.

Python in a coffee cup.
Image credits : 
Yuko Honda on Flickr. CC BY-SA 2.0
x

Subscribe now

Get the highlights in your inbox every week.

This is the tenth in a series of articles about features that first appeared in a version of Python 3.x. Some of these versions have been out for a while. Python 3.9 was first released in 2020 with cool new features that are still underused. Here are three of them.

Adding dictionaries

Say you have a dictionary with "defaults," and you want to update it with parameters. Before Python 3.9, the best option was to copy the defaults dictionary and then use the .update() method.

Python 3.9 introduced the union operator to dictionaries:

defaults = dict(who="someone", where="somewhere")
params = dict(where="our town", when="today")
defaults | params
    {'who': 'someone', 'where': 'our town', 'when': 'today'}

Note that the order matters. In this case, the where value from params overrides the default, as it should.

Removing prefixes

If you have done ad hoc text parsing or cleanup with Python, you will have written code like:

def process_pricing_line(line):
    if line.startswith("pricing:"):
        return line[len("pricing:"):]
    return line
process_pricing_line("pricing:20")
    '20'

This kind of code is prone to errors. For example, if the string is copied incorrectly to the next line, the price will become 0 instead of 20, and it will happen silently.

Since Python 3.9, strings have a .removeprefix() method:

>>> "pricing:20".removeprefix("pricing:")
'20'

Arbitrary decorator expressions

Previously, the rules about which expressions are allowed in a decorator were underdocumented and hard to understand. For example, while:

@item.thing
def foo():
    pass

is valid, and:

@item.thing()
def foo():
    pass

is valid, the similar:

@item().thing
def foo():
    pass

produces a syntax error.

Starting in Python 3.9, any expression is valid as a decorator:

from unittest import mock

item = mock.MagicMock()

@item().thing
def foo():
    pass
print(item.return_value.thing.call_args[0][0])
    <function foo at 0x7f3733897040>

While keeping to simple expressions in the decorator line is still a good idea, it is now a human decision, rather than the Python parser's option.

Welcome to 2020

Python 3.9 was released about one year ago, but some of the features that first showed up in this release are cool—and underused. Add them to your toolkit if you haven't already.

Hands on a keyboard with a Python book

Implementing data structures with dictionaries helps you access information more quickly.
Hands on a keyboard with a Python book

Explore some of the underutilized but still useful Python features.
Python programming language logo with question marks

Explore some of the underutilized but still useful Python features.
Business woman on laptop sitting in front of window

Explore some of the underutilized but still useful Python features.
Coding on a computer

Explore exception handling and other underutilized but still useful Python features.
old school calculator

Plus explore some of the underutilized but still useful Python features.
Hacker code matrix

Explore some of the underutilized but still useful Python features.
Computer screen with files or windows open

Explore os.fspath and two other underutilized but still useful Python features.
Hands on a keyboard with a Python book

Learn more about this and two other underutilized but still useful Python features.
Women in computing and open source v5

Explore positional-only parameters and two other underutilized but still useful Python features.

Topics

About the author

Moshe sitting down, head slightly to the side. His t-shirt has Guardians of the Galaxy silhoutes against a background of sound visualization bars.
Moshe Zadka - Moshe has been involved in the Linux community since 1998, helping in Linux "installation parties". He has been programming Python since 1999, and has contributed to the core Python interpreter. Moshe has been a DevOps/SRE since before those terms existed, caring deeply about software reliability, build reproducibility and other such things. He has worked in companies as small as three people and as big as tens of thousands -- usually some place around where software meets system administration...