ComparaisonComparaisons

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.

Sur cette page

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=True le 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

#
Python
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)
Résultatrésultat enregistré, vous pouvez le vérifier
Point(x=3, y=4) 3
Student(name='Léa', points=40)

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

#
Syntaxe
from collections import namedtuple
Name = namedtuple("Name", ["field1", "field2"])

from dataclasses import dataclass
@dataclass
class Name:
    field1: type
    field2: type

Plus d’exemples

#
namedtuple est immuable
Python
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)
Résultatrésultat enregistré, vous pouvez le vérifier
Le champ ne peut pas être modifié
Point(x=10, y=4)
dataclass ajoute facilement des méthodes et des valeurs par défaut
Python
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)
Résultatrésultat enregistré, vous pouvez le vérifier
Apprentissage de Python, étiquettes : 1
Task(title='Apprentissage de Python', tags=['python'])

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) ou typing.NamedTuple.
  • Créez toujours les champs ayant une valeur par défaut modifiable dans @dataclass (liste, dictionnaire) via field(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.