Another reason to use python 3.7
May 15, 2019
Python is amazing, python 3 even more amazing and any new version brings its batch of amazing novelties! And python 3.7 doesn’t break the rule. It is the first release implementing dataclasses
. This article is a short review of the new possiblities offered by this module.
Here is a example code:
class MyClassA():
def __init__(self, param_a, param_b, param_c=0):
self.param_a = param_a
self.param_b = param_b
self.param_c = param_c
def __repr__(self):
return "param_a=%s, param_b=%s, param_c=%s" % (
self.param_a,
self.param_b,
self.param_c
)
Do you have to write this type of code a lot of time? Then the following will be REALLY intesting for you!
Indeed, dataclasses
is THE tool to avoid repeating code in the __init__
, __repr__
and a couple more methods. The equivalent of the above code using dataclasses
is:
from dataclasses import dataclass
@dataclass
class MyClassA():
param_a: int
param_b: int
param_c: int = 0 # set a default value
if __name__ == '__main__':
mc = MyClassA(1, param_b=2)
print(mc)
And that’s all! The dataclass
decorator will automatically generate the __init__
and __repr__
methods that we had to write manually above.
You have noticed the annotations style introduced in python 3.4 to make clear to the user what are the expected type of the parameters. In case you do not want to specify them, you can use typings.Any
parameters, ie:
import typing
from dataclasses import dataclass
@dataclass
class MyClassA():
param_a: int
param_b: int
param_c: int = 0 # set a default value
param_d: typing.Any = None
Pretty cool? But what if I want to initialize other parameters that should not be modified through a init parameter? Easy, dataclasses
automatically generated __init__
method call a __post_init__
method where you can exactly do this. For instance:
from dataclasses import dataclass
@dataclass
class MyClassA():
param_a: int
param_b: int
param_c: int = 0 # set a default value
def __post_init_(self):
self.initial_sum = self.param_a + self.param_b
if __name__ == '__main__':
mc = MyClassA(1, param_b=2, param_c=10)
print(mc.initial_sum)
Apart from the obvious gain in time, dataclasses
also come with some helpful methods like:
from dataclasses import fields
fields(mc)
or:
from dataclasses import asdict
asdict(mc)
# {'param_a': 1, 'param_b': 2, 'param_c': 10}
Sooo, convinced?