Quite a lot has happened in the five recent releases of one of the world's most famous programming languages, Python. You should at least try to stay up to date with the fast-moving development, because it is an important IT tool for many years to come.
There are tons of new features in each release of Python, and not everything will be covered in this blog post. However, I will try to cover the features that I have found useful.
Python 3.6
F-strings
If you have not adopted f-strings yet, you should! Whenever you need to mix variables into strings, you can do so with f-strings. Simply put an f in front of the string and use curly braces around the variables.
You can tailor strings inside f-strings
>>> name = 'world'
>>> f'Hello, {name}!'
'Hello, world!'
or other values, like floats
>>> pi = 3.141592653
>>> f'the value of pi is {pi:.2f}'
'the value of pi is 3.14'
Annotate Parameter and Return Types
Annotations are purely decorational, and do not raise errors if the wrong type is given. However, they add a nice touch to the overall look of the code.
Since Python 3.5, annotations could be added to function parameters as follows.
def breakfast(eggs: int, bacon: bool) -> str:
recipe = f'Scramble {eggs} eggs'
if bacon:
recipe += ' and include bacon!'
return recipe
From Python 3.6, annotations can also be added to standalone variables.
weight: float = 3.4
length: float = 0.5
This feature strengthens the documentation of the code because the various intended variable types are specified where they are declared.
Python 3.7
Breakpoints
You can now use a built-in breakpoint() function.
def division(a, b):
breakpoint()
return a / b
division(3, 0)
When the code is run, you will find yourself inside a Python debugging shell.
-> return a / b
(Pdb)
The possible commands are:
c to continue.
q to quit.
n to go to the next line in this function.
s to go to the next line in this function or a called function.
So, when entering c, the code continues.
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
Dataclass Decorator
A Python class can be decorated as a dataclass, which is convenient, because a bunch of methods like __init__, logic operators __eq__, __ne__, __lt__, __le__. __gt__, __ge__, and __repr__ are added automatically.
from dataclasses import dataclass
@dataclass(order=True)
class Player:
username: str
strength: int
p1 = Player('zezima', 99)
p2 = Player('noob', 1)
print(p1 > p2) # True
print(p1 == p2) # False
print(p1) # Player(username='zezima', strength=99)
Python 3.8
The Walrus Operator
This operator resembles the eyes and tusks of a walrus, and it allows for more compact code.
>>> print(does_this_look_like_a_walrus := True)
True
Separation of Positional and Keyword Arguments
There are now two operators which can be used in, e.g., a function declaration:
Any arguments before / must be positional arguments.
Any arguments after * must be keyword arguments.
def lunch(positional, /, optional='spam', *, keyword='bread'):
return f'Eat {positional}, {optional}, and {keyword}'
# This works
print(lunch('egg')) # Eat egg, spam, and bread
print(lunch('egg', 'bacon')) # Eat egg, bacon, and bread
print(lunch('egg', optional='spam', keyword='bacon')) # Eat egg, spam, and bacon
# This does not work
print(lunch('egg', 'spam', 'tomato')) # TypeError: lunch() takes 2 positional arguments but 3 were given
print(lunch(positional='egg')) # TypeError: lunch() got some positional-only arguments passed as keyword arguments: 'positional'
Python 3.9
Time Zones
A crucial ingredient to dealing with datetime objects is time zones, which is now well supported in Python.
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
print(datetime.now(tz=timezone.utc))
# 2022-02-24 16:51:46.213733+00:00
print(datetime.now(tz=ZoneInfo("Europe/Oslo")))
# 2022-02-24 17:51:46.213807+01:00
The Union Operator for Dictionaries
Combine two dictionaries using the union operator.
suitcase = {'shirts': 2, 'socks': 3}
backpack = {'socks': 1, 'bottle': 1}
print(suitcase | backpack) # {'shirts': 2, 'socks': 1, 'bottle': 1}
print(backpack | suitcase) # {'socks': 3, 'bottle': 1, 'shirts': 2}
If the two dictionaries contain a common key (like 'socks' in the example above), the last dictionary will count towards the result. There is also the in-place union operator.
suitcase |= backpack
print(suitcase) # {'shirts': 2, 'socks': 1, 'bottle': 1}
Python 3.10
Stricter Zipping
Zipping lists or tuples are commonly used in Python. However, up until Python 3.10, this could potentially result in unforeseen bugs when the lists are of unequal length.
To overcome this, you can add the keyword argument strict to the built-in zip function.
drinks = ['soda', 'margarita', 'sake', 'wine']
foods = ['pizza', 'taco', 'sushi']
for drink, food in zip(drinks, foods, strict=True):
print(f'{drink} and {food}')
# soda and pizza
# margarita and taco
# sake and sushi
# Traceback (most recent call last):
# ...
# ValueError: zip() argument 2 is shorter than argument 1
Note that the first three pairs are printed, but when the fourth element, wine, is to-be printed, Python throws a ValueError.
Wildcards in Case Matching
In case matching, you can now match any case using the _ character, which acts as a wildcard:
def factorial(num: int) -> int:
if isinstance(num, int) and num >= 1:
match num:
case 1:
return 1
case _:
return num*factorial(num - 1)
print(factorial(4)) # 24
Further Reading: Full Release Posts by Python
Python 3.6 (23.12.2016): https://docs.python.org/3/whatsnew/3.6.html
Python 3.7 (27.06.2018): https://docs.python.org/3/whatsnew/3.7.html
Python 3.8 (14.10.2019): https://docs.python.org/3/whatsnew/3.8.html
Python 3.9 (05.10.2020): https://docs.python.org/3/whatsnew/3.9.html
Python 3.10 (04.10.2021): https://docs.python.org/3/whatsnew/3.10.html
I hope that you have at least found a couple of cool features to include in your codes. Will you actively discover the new features in Python 3.11, which will be released around October 2022?
Comments