Je voudrais savoir quelles sont les différences entre enum et namedtuple et quand on devrait utiliser l'un sur l'autre.
Comme analogie (quoique imparfaite), vous pouvez penser à enum.Enum
et namedtuple
in python as enum
and struct
in C. En d'autres termes, enum
s est un moyen des valeurs d'alias, tandis que namedtuple
est un moyen d'encapsuler les données par leur nom. Les deux ne sont pas vraiment interchangeables, et vous pouvez utiliser enum
s comme valeurs nommées dans un namedtuple
.
Je pense que cet exemple illustre la différence.
from collections import namedtuple
from enum import Enum
class HairColor(Enum):
blonde = 1
brown = 2
black = 3
red = 4
Person = namedtuple('Person', ['name','age','hair_color'])
bert = Person('Bert', 5, HairColor.black)
Vous pouvez accéder aux "attributs" nommés de la personne de la même manière qu'un objet normal.
>>> print(bert.name)
Bert
>>> print(bert.age)
5
>>> print(bert.hair_color)
HairColor.black
>>> print(bert.hair_color.value)
3
Souvent, vous ne voyez pas les namedtuple
comme ceci car le même concept essentiel peut être accompli en utilisant la déclaration class
plus largement connue. La définition class
ci-dessous se comporte presque de manière identique à la définition namedtuple
ci-dessus.
class Person:
def __init__(self, name, age, hair_color):
self.name = name
self.age = age
self.hair_color = hair_color
Cependant, une différence majeure entre un objet namedtuple
et un objet class
est que les attributs d'un namedtuple
ne peuvent pas être modifiés après sa création.
namedtuple est une structure rapide qui, en utilisant __ slots __ au lieu de __ dict __ , finalise le contenu que vous fournissez à l'initialisation (qui devient pratiquement en lecture seule, bien qu'il existe une méthode _replace ()).
Un tuple nommé est généralement utilisé lorsque vous avez besoin de nombreux (tels que des centaines, des milliers et même des millions) d'objets du même type ou lorsque vous lisez et/ou écrivez un enregistrement.
Par exemple, un exemple souvent cité est un point nommétuple qui pourrait être utilisé pour travailler avec un sommet de polygone avec son x, y, z
Composants.
La surcharge introduite par un tuple nommé sur un tuple standard est minime si on la compare à l'avantage de toujours pointer le bon composant par son nom (.x, .y, .z, .. .) au lieu de par index (0, 1, 2, ...).
La lecture de code tel que A.x est plus facile que A [0]: la signification est évidente, même des mois après avoir écrit le code et, mieux encore, pour d'autres programmeurs.
Ainsi, un tuple nommé est rapide, peut être utilisé pour identifier de manière significative le contenu du tuple et, enfin et surtout, peut coexister avec un code plus ancien accédant à un contenu de tuple par index.
from collections import namedtuple
Point = namedtuple('Point', 'x y z') # note the x, y, z fields
Origin = Point(0, 0, 0)
A = Point(1, 1, 1)
B = Point(1, 1, 0)
C = Point(1, 0, 0)
D = Point(1, 2, 3)
for p in (Origin, A, B, C, D):
print(p)
print('x:', p.x, ' y:', p.y, ' z:', p.z)
print('x:', p[0], ' y:', p[1], ' z:', p[2])
print()
En partant de l'exemple ci-dessus, dès que tout accède aux composants de points par nom plutôt que par index, d'autres modifications pourraient être introduites plus facilement, en n'entrant dans la modification d'aucun numéro d'index:
from collections import namedtuple
Point = namedtuple('Point', 'name x y z') # addition of the field 'name'
Origin = Point('O', 0, 0, 0)
A = Point('A', 1, 1, 1)
B = Point('B', 1, 1, 0)
C = Point('C', 1, 0, 0)
D = Point('D', 1, 0, 1)
for p in (Origin, A, B, C, D):
print(p)
print(p.name) # more readable than p[0] that is no more the x coordinate
print('x:', p.x, ' y:', p.y, ' z:', p.z) # unchanged
print('x:', p[1], ' y:', p[2], ' z:', p[3]) # changed
print()
Une énumération est un moyen de coupler des noms symboliques à des valeurs constantes et de les classer comme un ensemble spécifique. Nous définissons une énumération en créant une classe dérivée de Enum ou IntEnum , en fonction des valeurs que nous voulons que nos constantes aient: Enum est la version générique, IntEnum impose le fait que chaque valeur constante sera de type int.
Par exemple, les énumérations sont bonnes pour définir les couleurs par nom, types d'entiers spécifiques, sexe ou, encore une fois - plus généralement - éléments appartenant à un ensemble spécifique.
from enum import Enum, IntEnum, unique
class Color_1(Enum):
red = 'red'
green = 'green'
blue = 'blue'
class Color_2(Enum):
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
class Color_3(IntEnum):
red = 0xFF0000
green = 0xFF00
blue = 0xFF
class Gender_1(Enum):
unknown = 'U'
male = 'M'
female = 'F'
class Gender_2(Enum):
unknown = 0.3
male = 0.5
female = 0.7
class Shape(Enum): # Note the different constants types, perfectly legal
TRIANGLE = 't'
RECTANGLE = 5
SQUARE = Tuple('square')
class DataType(IntEnum):
int8 = -8
int16 = -16
int32 = -32
int64 = -64
int = -2
negative = -1
positive = 1
uint = 2
uint8 = 8
uint16 = 16
uint32 = 32
uint64 = 64
Dans le développement Pythonic - les éléments d'énumération peuvent avoir une valeur spécifique assignée - qui peut être unique ou non, selon vos préférences et vos spécifications. Le décorateur nique est utilisé pour appliquer l'unicité des valeurs. Par défaut, il est possible d'attribuer la même valeur constante à deux ou plusieurs noms symboliques différents.
class Color_4(IntEnum):
red = 1
green = 2
blue = 3
RED = 1
GREEN = 2
BLUE = 3
Les éléments d'énumération peuvent être comparés entre eux, mais pour qu'ils réussissent, non seulement la valeur doit correspondre, même leur type doit être le même.
Par exemple:
Color_4.red == Color_4.RED
renverra True (même classe, même valeur), mais ce qui suit:
Shape.SQUARE == Tuple('square')
sera False - car l'élément droit de la comparaison - Tuple ('square') - n'est pas de type Shape, bien que les deux aient la même valeur.
Pour conclure, les énumérations et les nommés sont des instruments différents.
Des énumérations ont été ajoutées récemment à Python (recherche PEP435). Si la mémoire me convient, les nommés sont disponibles depuis assez longtemps, mais je suis toujours un débutant dans la communauté, donc je peux me tromper HTH