Python 3.9 was released in October 2020 and comes with several new features that make coding easier and more efficient. In this response, we will take a closer look at some of the most notable changes.
Dictionary Union
One of the most exciting new features in Python 3.9 is the dictionary union operator. This feature merges two dictionaries and returns a new dictionary. If a key appears in both dictionaries, the value from the right-hand operand will be in the final dictionary.
For example:
>>> dict_1 = {'John': 100, 'Jonny': 200, 'David': 300}
>>> dict_2 = {'Elon': '500', 'Jonny': '400'}
>>> dict_1 | dict_2
Output: {'John': 100, 'David': 300, 'Elon': '500', 'Jonny': '400'}
Additionally, this feature also has an augmented assignment version, which is similar to the list += and list.extend methods. The augmented assignment accepts any iterable and not just dictionaries.
For example:
>>> dict_1 |= [('Olivia', 900)]
>>> dict_1
Output: {'John': 100, 'David': 300, 'Elon': '500', 'Jonny': '400', 'Olivia', 900}
It is important to note that the union operator only works with dictionary operands. If you try to use it with any other operand, it will throw a TypeError.
# Union will only work with dict operands.
>>> dict_1 | [('Olivia', 900)]
# Output: TypeError: can only merge dict (not "list") to dict
Furthermore, dict union is not commutative, meaning that the order of the operands will affect the outcome of the merged dictionary. This is because the last-seen value of a key will be the one that is retained in the final dictionary.
String methods to remove prefixes and suffixes
Python 3.9 comes with two new string methods, removeprefix() and removesuffix(), that remove prefixes and suffixes from a string if they are present.
For example:
>>> "NeptuneWorld".removeprefix("Nep")
Output: tuneWorld
>>> “NeptuneWorld”.removesuffix(“World”)
Output: Neptune
These methods also work in cases where you want to remove multiple copies of prefixes and suffixes. This is especially useful when dealing with strings that have a lot of unnecessary text at the beginning or end.
For example:
>>> s = "NeptuneWorld"
>>> s.removeprefix("Nep")
# Output: 'tuneWorld'
>>> s.removesuffix("World")
# Output: 'Neptune'
Type Hinting
Python is a dynamically typed language, meaning that you do not need to specify the variable type. However, since Python 3.5, you have been able to define the type of variables. In Python 3.9, you can see the type of variable that a function expects.
def fun_add(val: int):
return val + val
print(fun_add('Hi'))
TypeError: unsupported operand type(s) for +: 'int' and 'str'
In addition to this, Python 3.9 also introduced support for dictionary and tuple types in type hints.
For example:
def fun_add_dict(val: dict[str, int]):
return sum(val[dict_key] for dict_key in val)
fun_add_dict({“one”:1, “two”:2})
Output: 3
Speed Improvements
Python 3.9 has improved the speed of several built-in functions, including range(), tuple(), set(), frozenset(), list(), and dict(), using vectorcall. Vectorcall is a new calling convention that reduces the cost of calling C functions from Python, resulting in faster execution.
Here is an example of using the improved range() function:
from timeit import timeit
>>> timeit('for i in range(1000000): pass', number=1000)
0.0437114
>>> timeit('for i in range(0, 1000000): pass', number=1000)
0.03530880000000002
>>> timeit('for i in range(0, 1000000, 1): pass', number=1000)
0.04036579999999999
As you can see, the new implementation of range() is faster than the old implementation, especially when using a step parameter.