namedtuple vs dataclass
namedtuple crée un tuple léger et immuable à champs nommés ; @dataclass crée une classe ordinaire et modifiable avec __init__, __repr__ et __eq__ générés.
Comparaison point par point
#Hérite de
- collections.namedtuple
tuple- @dataclass
- Classe ordinaire (
object)
Les champs peuvent être modifiés après création
- collections.namedtuple
- Non
- @dataclass
- Oui (par défaut),
frozen=Truele bloque
Indexation et déballage comme un tuple
- collections.namedtuple
- Oui
- @dataclass
- Non
Clé de dictionnaire ou élément d’un ensemble
- collections.namedtuple
- Oui
- @dataclass
- Seulement avec
frozen=True
Valeur par défaut qui est une liste
- collections.namedtuple
- Via
defaults=[...]pour les derniers champs - @dataclass
- Via
field(default_factory=list)
Usage typique
- collections.namedtuple
- Données légères et fixes : résultat de fonction, ligne CSV
- @dataclass
- Données qui changent, méthodes propres, validation
Exemple
#from collections import namedtuple
from dataclasses import dataclass
Point = namedtuple("Point", ["x", "y"])
@dataclass
class Student:
name: str
points: int = 0
point = Point(3, 4)
student = Student("Léa")
student.points += 40
print(point, point[0])
print(student)Définition et utilisation
#Les deux constructions éliminent le code répétitif pour les classes qui servent surtout à stocker des données : vous déclarez les champs une fois, et __init__, un __repr__ lisible et la comparaison __eq__ sont générés automatiquement.
Elles diffèrent par ce qu’est vraiment l’objet résultant. namedtuple crée une classe qui hérite de tuple : l’objet est immuable, on peut l’indexer, le déballer et l’utiliser comme clé de dictionnaire, mais modifier un champ se termine par une AttributeError. @dataclass crée une classe ordinaire : l’objet est modifiable, sauf si vous ajoutez frozen=True, ce n’est pas un tuple, donc vous ne l’indexez pas par un nombre, mais il est facile de lui ajouter des méthodes, des valeurs par défaut via field(default_factory=...) et une validation dans __post_init__.
Choisissez namedtuple quand les données sont simples, fixes et doivent être légères, par ex. le résultat d’une fonction qui renvoie plusieurs valeurs ou une ligne d’un fichier CSV. Choisissez @dataclass quand la classe doit changer pendant l’exécution du programme, a besoin de ses propres méthodes ou de valeurs par défaut comme une liste ou un dictionnaire.
Syntaxe
#from collections import namedtuple
Name = namedtuple("Name", ["field1", "field2"])
from dataclasses import dataclass
@dataclass
class Name:
field1: type
field2: typePlus d’exemples
#from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
point = Point(3, 4)
try:
point.x = 10
except AttributeError:
print("Le champ ne peut pas être modifié")
moved = point._replace(x=10)
print(moved)from dataclasses import dataclass, field
@dataclass
class Task:
title: str
tags: list = field(default_factory=list)
def summary(self):
return f"{self.title}, étiquettes : {len(self.tags)}"
task = Task("Apprentissage de Python")
task.tags.append("python")
print(task.summary())
print(task)Bonnes pratiques
#- namedtuple est pratique pour renvoyer plusieurs valeurs d’une fonction : vous déballez le résultat comme un tuple, ou vous le lisez par les noms des champs.
- Si vous avez besoin d’immuabilité, mais aussi de méthodes et d’une syntaxe plus récente avec des types, envisagez
@dataclass(frozen=True)outyping.NamedTuple. - Créez toujours les champs ayant une valeur par défaut modifiable dans
@dataclass(liste, dictionnaire) viafield(default_factory=...), sinon vous obtenez une erreur dès la définition de la classe.
Entrées associées
#Vous voyez une erreur ou il manque un exemple ? Écrivez-nous.