Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Nouveauté de la version 3.7

Python 3.7 apporte un nouveauté pour simplifier la définition de classes dites “de données” ; ce type de classes s’applique pour des objets qui sont essentiellement un assemblage de quelques champs de données.

Licence CC BY-NC-ND Thierry Parmentelat & Arnaud Legout Inria - UCA

Aperçu

La raison d’être de dataclass est de fournir - encore un - moyen de définir des classes d’enregistrements.

Voici par exemple comment on pourrait définir une classe Personne:

from dataclasses import dataclass
@dataclass
class Personne:
    nom: str
    age: int
    email: str = ""

Personne(nom='jean', age=12)
Personne(nom='jean', age=12, email='')

Comme vous le voyez, on n’a pas eu besoin d’implémenter une dunder __repr__ pour obtenir une présentation déjà plus agréable que <__main__.Personne at 0x10ac991e0>

Surcharge

On n’est pas obligé d’adopter toutes les dunder automatiques; par exemple je peux toujours définir mon propre repr() comme d’habitude :

@dataclass
class PrettyPersonne:
    nom: str
    age: int
    email: str = ""

    def __repr__(self):
        return f"{self.nom} <{self.email}>, {self.age} ans"

PrettyPersonne(nom='alice', age=25, email='alice@example.com')
alice <alice@example.com>, 25 ans

Une fois qu’on a dit ça, il me semble personnellement plus propre d’être explicite, et d’indiquer au décorateur qu’on va se charger du repr; mais bon...

# on peut aussi être plus explicite
@dataclass(repr=False)
class PrettyPersonne:
    nom: str
    age: int
    email: str = ""

    def __repr__(self):
        return f"{self.nom} <{self.email}>, {self.age} ans"

PrettyPersonne(nom='alice', age=25, email='alice@example.com')
The history saving thread hit an unexpected error (OperationalError('attempt to write a readonly database')).History will not be written to the database.
alice <alice@example.com>, 25 ans

Instances non mutables

En fait ça va beaucoup plus loin que cela, la dataclasse se retrouve avec pas mal de dunder méthodes implémentées gratuitement pour nous.

Nous reprenons ici le même scénario d’ensemble de points que nous avons déjà rencontré plusieurs fois; remarquez que la classe Point sait correctement comparer et hasher ses objets, et on va pouvoir les ranger dans un ensemble pour éliminer les doublons, sans avoir besoin de redéfinir les dunder __eq__ et __hash__ qu’il aurait fallu faire si on n’avait pas utilisé dataclass :

Enfin on illustre ici le fait que décorateur dataclass accepte divers arguments pour choisir le comportement de certains aspects de la classe. Reportez-vous à la documentation pour une liste complète, mais voici un exemple qui utilise frozen=True qui nous permet de créer des instances non mutables.

from dataclasses import dataclass

@dataclass(frozen=True)
class Point:
    x: float
    y: float
p1, p2, p3 = Point(1, 1), Point(1, 1), Point(1, 1)
s = {p1, p2}
len(s)
1
p3 in s
True
try:
    p1.x = 10
except Exception as e:
    print(f"OOPS {type(e)}")
OOPS <class 'dataclasses.FrozenInstanceError'>

Résumé

Donc bref, j’espère vous avoir convaincu que ce trait de dataclass permet d’éviter pas mal de code de type boilerplate, et comme chacun sait: less code, fewer bugs, donc n’hésitez pas à user et abuser de ce trait, d’autant qu’à présent la version 3.7 est largement acquise !

Pour aller plus loin

Vous pouvez vous rapporter