New Features in Python 3.9 You Should Know About

Python 3.9 Beta is coming soon, so it’s time to explore some of its upcoming features like new dict operators, new functools and more…

The release of Python 3.9 is still quite a while away (5.10.2020), but with the last alpha (3.9.0a5) release out and first beta in near future, it feels like it’s time to see what new features, improvements and fixes we can expect and look forward to. This article won’t be an exhaustive list of every change, but rather a list of the most interesting and noteworthy things to come with the next version for us — developers. So, let’s dive in!

Original Photo by David Clode on Unsplash

Installing Beta Version

To be able to actually try anything contained in the alpha/beta versions of Python 3.9, we first need to install it. Ideally alongside our existing Python 3.8 (or another stable version) installation so that we don’t mess up our default interpreter. So, to install the latest, greatest version:

After running this you should be greeted by IDLE and message like:

New Dict Operators

The most notable new feature is probably the new dictionary merging operator — | or |=. Until now, you would have to choose from one of the following 3 options for merging dictionaries:

The first option above uses dict(iterable, **kwargs) function which initializes dictionaries - the first argument is a normal dictionary and the second one is a list of key/value pairs, in this case, it's just another dictionary unpacked using ** operator.

The second approach uses update function to update the first dictionary with pairs from the second one. As this one modifies dictionary in-place, we need to copy the first one into the final variable to avoid modifying the original.

Third — last — and in my opinion, the cleanest solution is to use dictionary unpacking and unpack both variables ( d1 and d2) into the resulting one d.

Even though the options above are completely valid, we now have a new (and better?) solution using | operator.

The first example above does very much the same as operator unpacking shown previously ( d = {**d1, **d2}). The second example, on the other hand, can be used for in-place merging, where the original variable ( d1) is updated with values from the second operand ( d2).

Topological Ordering

Next new interesting (and little obscure) feature is part of functools module. You can find it under TopologicalSorter class. This class allows us to sort graphs using topological ordering. What is that? you may ask. Topological ordering is such ordering where for 2 nodes u and v connected by directed edge uv (from u to v), u comes before v.

Before the introduction of this feature, you would have to implement it yourself using e.g. Khan’s algorithm or depth-first search which aren’t exactly simple algorithms. So, now in case need to — for example — sort dependant jobs for scheduling, you just do the following:

In the example above, we first create a graph using a dictionary, where keys are outgoing nodes and values are sets of their neighbours. After that, we create an instance of sorter using our graph and then call static_order function to produce the ordering. Bear in mind that this ordering may depend on the order of insertion because when 2 nodes are in the same level of the graph, they are going to be returned in the order they were inserted in.

Apart from static ordering, this class also supports parallel processing of nodes as they become ready for processing, which is useful when working with e.g. task queues — you can find examples of that in Python library docs here.

IPv6 Scoped Addresses

Another change introduced in Python 3.9 is the ability to specify the scope of IPv6 addresses. In case you are not familiar with IPv6 scopes, they are used to specify in which part of the internet is the respective IP address valid. Scope can be specified at the end of IP address using % sign - for example: 3FFE:0:0:1:200:F8FF:FE75:50DF%2 - so this IP address is in scope 2 which is link-local address.

So, in case you need to deal with IPv6 addresses in Python, you can now do so like this:

There is one thing you should be careful with when using IPv6 scopes though. Two addresses with different scopes are not equal when compared using basic Python operators.

New math Functions

Meanwhile in the math module, a bunch of miscellaneous functions were added or improved. Starting with the improvement to one existing function:

Previously, the gcd function which calculates the Greatest Common Divisor could only be applied to 2 numbers, forcing programmers to do something like this math.gcd(80, math.gcd(64, 152)), when working with more numbers. Starting with Python 3.9, we can apply it to any number of values.

The first new addition to math module is math.lcm function:

math.lcm calculates Least Common Multiple of its arguments. Same as with GCD, it allows a variable number of arguments.

The 2 remaining new functions are very much related. These are math.nextafter and math.ulp:

The math.nextafter(x, y) function is pretty straightforward - it's next float after x going towards y while taking into consideration floating-point number precision.

The math.ulp on the other hand, might look a little weird... ULP stands for "Unit in the Last Place" and it's used as a measure of accuracy in numeric calculations. The shortest explanation is using an example:

Let’s imagine that we don’t have 64 bit computer. Instead, all we have is just 3 digits. With these 3 digits, we can represent a number like 3.14, but not 3.141. With 3.14, the nearest larger number that we can represent is 3.15, These 2 numbers differ by 1 ULP (Units at the last place), which is 0.1. So, what the math.ulp returns is equivalent of this example, but with actual precision of your computer. For proper example and explanation see nice writeup at

New String Functions

math module is not the only one that got some new functions. Two new convenience functions for strings were added too:

These 2 functions perform what you would otherwise achieve using string[len(prefix):] for prefix and string[:-len(suffix)] for suffix. These are very simple operations and therefore also very simple functions, but considering that you might perform these operations quite often, it’s nice to have built-in function that does it for you.

Bonus: HTTP Codes

Last but not least, well actually… are HTTP status codes added to http.HTTPStatus. Namely, those are:

Looking at these status codes, I can’t quite see why would you ever use them. That said, it’s great to finally have I’m a Teapot status code at our disposal. It’s a great quality of life improvement that I can now use http.HTTPStatus.IM_A_TEAPOT when returning this code from production server ( sarcasm, Please never do that...).


Probably not all of these changes are relevant to your daily programming, but I think it’s good to be at least aware of the first 2 additions (| operator and TopologicalSorter) as they might come in handy at some point. That said Python 3.9 is still in alpha phase, so there still might be some additional changes up until 18.5.2020 (first beta release). But even then you should not use this version, as it is not stable nor production ready (not at least until October).

If you liked this article you should check you other of my Python articles below!


Certified Red Hat Professional | DevOps Engineer at IBM | Working with Python, JavaScript, Kubernetes, OpenShift, Docker and more |

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store