Top 6 Most Useful Python 3.9 Features

Filed Under: Python
Top 6 Most Useful Python 3 9 Features

Our favorite programming language, Python, just got a major update. Python 3.9 is out with a bunch of useful features!

So, after using the newest version for some time, I decided to write this article and summarize all the feature updates that have been released in Python 3.9 for everyone to understand.

Summary of Python 3.9 Features

There are a few important changes that programmers use regularly. We’ll go over those first and at the end, look at the features that are not as commonly used.

  1. PEP 584, Dictionary Union Operators
  2. PEP 585, Type Hinting Generics In Standard Collections
  3. PEP 615, IANA Time Zone Database included in the standard library in the zoneinfo module
  4. PEP 616, String methods to remove prefixes and suffixes
  5. PEP 617, New Python parser
  6. Better modules for Greatest Common Divisor (GCD) and Least Common Multiple (LCM)

Easier Way to Merge and Update Dictionaries (PEP 584)

Merge Dictionaries Python Feature Update 3 9
Merge Dictionaries Python Feature Update 3 9

Python already had a few ways to merge two or more dictionaries. But there were a few issues with those.

  • The dict1.update(dict2) method – You can merge only two dictionaries at once and this method requires a temporary variable to store the merged dictionary.
  • Dict unpacking method (**dict1, **dict2) – This method ignores the types of mappings. It fails for dict subclasses such as defaultdict that have an incompatible __init__ method
  • ChainMap(dict1, dict2) method – Chaimap variables are wrappers of the original dictionaries. So any changes to the ChainMap will modify the original dictionaries.

The Python Dictionary Union Operator

There was no unified method for merging two dictionaries in Python. But now Python 3.9 features introduce the Dictionary Union Operator ( | ).

Consider this example below:

>>> d = {'spam': 1, 'eggs': 2, 'cheese': 3}
>>> e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
>>> d | e
{'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}
>>> e | d
{'cheese': 3, 'aardvark': 'Ethel', 'spam': 1, 'eggs': 2}

# Augmented assignment operator
>>> d |= e
>>> d
{'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}

The first two examples show how the dictionary union operator obeys the order of the items in the dictionary.

So whichever dictionary stands first, the dictionary items from it are pulled out and the second dictionary’s elements are appended to the first one.

The third example is the augmented assignment operator, similar to the += or -=.

It assigns the merged dictionary to the variable without needing a third variable.

Type Hinting Generics In Standard Collections (PEP 585)

Type Hinting Update Python 3 9 Features
Type Hinting Update Python 3 9 Features

Previously, static typing has been built on top of the existing python runtime incrementally.

As a consequence, collection hierarchies got progressively duplicated, as a program could use the module’s types at the same time as the built-in ones.

This created a bit of confusion, as we had two parallel type systems, not really competing ones, but we always had to keep an eye out for that parallelism. There were even cheatsheets.

Well, now this is over.

By moving the generics to the standard collections, this makes it easier to annotate the programs, as there’s no need anymore for a parallel type hierarchy in the typing module.

This allows for using the same type of syntax in all contexts.

An example of types that you would previously have to import from typing to make use of would be List, Dict, Set, Tuple, Optional, just as an example. Right now, you can just import them as a generic list or dict, set, tuple, optional, etc.

So, you stop using:


And use instead the much simpler:


Attention, this will not generate DeprecationWarnings, as one could expect in this context.

The intention is to minimize the runtime impact of typing, so even though importing from typing is deprecated, the deprecation will not generate DeprecationWarnings.

This is more important the bigger your program or project is, so if you’re running a production operation, you should see that this deprecation behavior gets handled correctly.

In-built Time Zone Support in the zoneinfo Module (PEP 615)

Built In Timezone Support Python 3 9
Built In Timezone Support Python 3 9

Timezones are always a big headache for programmers, and this library aims to make life a bit easier. Zoneinfo allows one to gather time information about certain timezones.

It has a database of timezones that gets synchronized, more specifically, the IANA timezone database. This has now been added to the standard library, making it easier to access.

This is the general way it works: the zoneinfo module will use the system’s time zone by default. If there is no system timezone available, it will then use tzdata as the timezone.

Here’s an example:

import zoneinfo
import datetime
myzone = zoneinfo.ZoneInfo("America/Los_Angeles")

The above shown code creates an object with zoneinfo information based on the NY timezone. It then prints a datetime object based on that zone.

You may need to pip install tzdata first, before getting the available timezone servers.

String methods to remove prefixes and suffixes (PEP 616)

String Methods To Remove Prefix And Suffix
String Methods To Remove Prefix And Suffix

Many times we need to handle strings in a straightforward, legible way, that gets the job done, but doesn’t pollute the code.

While we always had methods to manipulate strings in Python, when handling big lists of webpages or large databases, it’s very often that we find cases when we need to massage the inputs a little bit. Very often we need to remove prefixes or suffixes.

These are common manipulations, either for small local websites or in Big Data storage systems. And strings may be marked with a residue of their origin or superfluous information we may need to get rid of at some point.

Whatever the case may be, we have two new methods that allow for a certain elegance while doing so, such as removing prefixes and removing suffixes.

Here’s an example for the prefix removal:

golden = ["golden-ring", "golden-earring", "golden-necklace"]
for gold in golden:
   not_golden = gold.removeprefix("golden-")

The result is:


Here’s another example for removing suffixes. You’ll see that the workings are generally the same:

jams = ["strawberry-jam", "raspberry-jam", "orange-jam"]
for jam in jams:
   fruit = jam.removesuffix("-jam")

The result is:


The previous ways or manipulating strings in Python are of course still valid, but these new ones work as valid shortcuts, and will surely come in handy. At the least, they contribute to much cleaner, maintainable code in the long run.

New parser (PEP 617)

Updated Parser In Python 3 9
Updated Parser In Python 3 9

One of the most fundamental parts of any programming language is the parser.

Python 3.9 brings a profound new feature that will not be visible to the naked eye but will accompany us throughout our daily back and forth with the language.

There has been a reimplementation of the parser and a fairly deep one at that.

Python has been using a LL(1) parser (this means “Left-to-right, Leftmost derivation, top-down parser). For a long while now, this has been used to parse code into parse trees.

Its basic operation is reading one character at a time, and figuring out how the source code should be interpreted, without backtracking.

Using a simple parser has its advantages.

  • One of them is the fact that it’s more straightforward in implementation and reasoning.
  • One of the disadvantages is, when you hit edge cases, it may need some special treatment to take care of that specific case.

PEG (parsing expression grammar) parsers were investigated to see if they could bring a specific advantage to Python by trying to achieve a good balance between power and complexity.

PEG parsers are indeed more powerful, but they introduce another level of complexity which may be hard to deal with.

The latest version comes with two parsers: the previous one and the new one.

The main idea is for both the PEG parser and the LL(1) parser to produce the same AST, which is the abstract syntax tree.

The PEG parser is now the default. However, if you still want to run with the old parser, you can do so, for the time being. Just use -X oldparser as a runtime option, like this:

python -X oldparser

If you are in a situation where you’ll be using that a lot and may not want to specify the flag at each invocation, you can set the PYTHONOLDPARSER environment variable that exists for this purpose, like this:


or, in fact, to any non-empty string value.

For now, the new parser is the default, and the old one may still be accessed and used.

This allows for comparison, testing, or whatever you may need to validate that the new parser does not bring problems to your infrastructure.

If it does, you have the tools and the ability to address them, as the old parser is bound to be removed on Python 3.10.

This coexistence of parsers is just to get us warmed up.

When the LL(1) parser is no longer around, new features can be implemented into the parser that require the complexity that the PEG parser can handle, such as structural pattern matching.

In terms of speed, there’s no big difference between the two, PEG may perform slightly faster, but it shouldn’t be anything noticeable.

Greatest Common Divisor (GCD) and Least Common Multiple (LCM)

GCD And LCM Calculation
GCD And LCM Calculation

There has been a modification to existing Python math functions that calculate the Greatest Common Divisor (GCD) and Least Common Multiple (LCM), to make the functions more powerful.

These are important functions, despite the fact that may not be apparent for some people at first sight.

But the divisors and multiples of a number are important properties, which are used in applications such as cryptography, and others, that use the concept of prime numbers to calculate encryption keys.

Here’s an example:

>>> import math
>>> math.gcd(24, 12)

The GCD of 24 and 12 is 6 because 6 is the largest number that divides both 24 and 12.

The least common multiple (LCM) is related to GCD. The LCM of two numbers is the smallest number that can be divided by both. In the new Python 3.9 features, you no longer need to define your own LCM function:

>>> import math
>>> math.lcm(49, 14)

The least common multiple of 49 and 14 is 98 because 98 is the smallest number that can be divided by both 49 and 14.

In earlier versions of Python, the functions existed to calculate GCD and LCM but accepting only two numbers. Starting this version, you can have any arbitrary number of arguments.

So you would have this code:

>>> import math
>>> math.gcd(math.gcd(273, 1729), 6048)

But now you can have this code:

>>> import functools
>>> functools.reduce(math.gcd, [273, 1729, 6048])


That’s all for the Python 3.9 features. Python is certainly one of the most well-received language in this decade. And with the inevitability of Machine learning, there’s no reason for Python to stop being popular in the near future.

You can learn a lot more about Python on Journaldev.


  1. sahoo says:

    the time module is not working and in remove suffix(there are 3 letters), it will be suffix..pls correct the time module it is interesting…

    1. Ninad says:

      Hi sahoo,

      Thanks for bringing that up! Both the time and the suffix code works now


Leave a Reply

Your email address will not be published. Required fields are marked *

Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages