PEP-557 a introduit les classes de données dans Python bibliothèque standard, qui peut essentiellement remplir le même rôle que collections.namedtuple
et typing.NamedTuple
. Et maintenant, je me demande comment séparer les cas d'utilisation dans lesquels namedtuple est toujours une meilleure solution.
Bien sûr, tout le crédit va à dataclass
si nous avons besoin de:
property
décorateurs, attributs gérablesLes avantages des classes de données sont brièvement expliqués dans le même PEP: Pourquoi ne pas simplement utiliser namedtuple .
Mais que diriez-vous d'une question opposée pour les couples nommés: pourquoi ne pas simplement utiliser la classe de données? Je suppose que namedtuple est mieux du point de vue des performances, mais n'a encore trouvé aucune confirmation à ce sujet.
Prenons la situation suivante:
Nous allons stocker les dimensions des pages dans un petit conteneur avec des champs définis statiquement, taper des indications et un accès nommé. Aucun autre hachage, comparaison, etc. n'est nécessaire.
Approche NamedTuple:
from typing import NamedTuple
PageDimensions = NamedTuple("PageDimensions", [('width', int), ('height', int)])
Approche DataClass:
from dataclasses import dataclass
@dataclass
class PageDimensions:
width: int
height: int
Quelle solution est préférable et pourquoi?
P.S. la question n'est pas un doublon de celui-là de quelque manière que ce soit, car ici je pose des questions sur les cas dans lesquels namedtuple est mieux, pas sur la différence (J'ai vérifié les documents et les sources avant de demander)
Cela dépend de vos besoins. Chacun d'eux a ses propres avantages.
Voici une bonne explication des Dataclasses sur PyCon 2018 Raymond Hettinger - Dataclasses: Le générateur de code pour terminer tous les générateurs de code
Dans Dataclass, toute implémentation est écrite en Python, comme dans Namedtuple, tous ces comportements sont gratuits car Namedtuple est hérité de Tuple. Et la structure de Tuple est écrite en C, c'est pourquoi les méthodes standard sont plus rapides dans Namedtuple (hachage, comparaison, etc.).
Mais Dataclass est basé sur dict comme Namedtuple basé sur Tuple. Selon cela, vous avez des avantages et des inconvénients à utiliser ces structures. Par exemple, l'utilisation de l'espace est plus petite dans NamedTuple, mais l'accès au temps est plus rapide dans Dataclass.
Veuillez voir mon expérience:
In [33]: a = PageDimensionsDC(width=10, height=10)
In [34]: sys.getsizeof(a) + sys.getsizeof(vars(a))
Out[34]: 168
In [35]: %timeit a.width
43.2 ns ± 1.05 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [36]: a = PageDimensionsNT(width=10, height=10)
In [37]: sys.getsizeof(a)
Out[37]: 64
In [38]: %timeit a.width
63.6 ns ± 1.33 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
Mais avec l'augmentation du nombre d'attributs du temps d'accès NamedTuple reste le même petit, car pour chaque attribut, il crée une propriété avec le nom de l'attribut. Par exemple, pour notre cas, la partie de l'espace de noms de la nouvelle classe ressemblera à:
from operator import itemgetter
class_namespace = {
...
'width': property(itemgetter(0, doc="Alias for field number 0")),
'height': property(itemgetter(0, doc="Alias for field number 1"))**
}
Dans quels cas nommé tuple est-il toujours un meilleur choix?
Lorsque votre structure de données doit/peut être immuable, lavable, itérable, déballable, comparable, vous pouvez utiliser NamedTuple. Si vous avez besoin de quelque chose de plus compliqué, par exemple, une possibilité d'héritage pour votre structure de données, utilisez alors Dataclass.
Dans la programmation en général, tout ce qui PEUT être immuable DEVRAIT être immuable. Nous gagnons deux choses:
C'est pourquoi, si les données sont immuables, vous devez utiliser un tuple nommé au lieu d'une classe de données
Je l'ai écrit dans le commentaire, mais je vais le mentionner ici: vous avez certainement raison qu'il y a un chevauchement, en particulier avec frozen=True
dans les classes de données - mais il y a toujours des fonctionnalités telles que le déballage appartenant aux nommés et qui sont toujours immuables - je doute qu'ils suppriment les nommés en tant que tels