
Une énumération est un ensemble fixe de valeurs nommées et constantes, regroupées dans une seule classe. Au lieu de disperser des constantes magiques ("publie", 200, 0644) dans votre code, vous les rassemblez sous un type unique, lisible et vérifiable. Le module enum de la bibliothèque standard fournit tout le nécessaire : la classe de base Enum, les variantes typées IntEnum et StrEnum, les indicateurs de bits Flag et IntFlag, plus les outils auto() et @unique. Ce guide couvre chacun de ces éléments avec du code exécutable.
Il s'adresse aux développeurs qui manipulent des statuts, des codes de retour, des niveaux de priorité ou des combinaisons d'options, et qui veulent remplacer leurs chaînes ou entiers en dur par des valeurs robustes. Les exemples ont été exécutés avec Python 3.12.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Créer une énumération avec
enum.Enumet lire ses membres via.nameet.value. - Itérer, comparer et accéder aux membres par nom ou par valeur.
- Générer des valeurs avec
auto()et garantir l'unicité avec@unique. - Choisir entre
IntEnum,StrEnum,FlagetIntFlagselon le besoin. - Combiner des options par opérations sur les bits et ajouter des méthodes à une énumération.
- Décider quand une énumération vaut mieux que de simples constantes.
Qu'est-ce qu'une énumération
Section intitulée « Qu'est-ce qu'une énumération »Une énumération (souvent abrégée enum) est une classe qui hérite de enum.Enum et dont chaque attribut devient un membre constant. Chaque membre possède deux propriétés : son nom (.name, la chaîne de gauche) et sa valeur (.value, l'objet de droite). L'exemple ci-dessous modélise le statut d'un article de blog.
from enum import Enum
class Statut(Enum): BROUILLON = "brouillon" PUBLIE = "publie" ARCHIVE = "archive"
print(Statut.PUBLIE) # Statut.PUBLIEprint(Statut.PUBLIE.name) # PUBLIEprint(Statut.PUBLIE.value) # publieprint(repr(Statut.PUBLIE)) # <Statut.PUBLIE: 'publie'>Chaque membre est une instance unique de la classe, créée une seule fois au chargement. Ce point est fondamental : deux références au même membre pointent vers le même objet en mémoire, ce qui rend la comparaison rapide et sûre.
Accéder aux membres et les comparer
Section intitulée « Accéder aux membres et les comparer »Un membre d'énumération se récupère de trois façons : par attribut (Statut.PUBLIE), par valeur avec un appel (Statut("publie")), ou par nom avec des crochets (Statut["PUBLIE"]). La forme par valeur sert typiquement à reconstruire un membre depuis une donnée lue en base ou dans un fichier JSON.
print(Statut("publie")) # Statut.PUBLIE (recherche par valeur)print(Statut["PUBLIE"]) # Statut.PUBLIE (recherche par nom)Comme chaque membre est un singleton, la comparaison d'identité is est la manière idiomatique de tester un statut. L'égalité == fonctionne aussi, mais is exprime clairement qu'on compare des constantes.
print(Statut.PUBLIE is Statut.PUBLIE) # Trueprint(Statut.PUBLIE == Statut.ARCHIVE) # FalseItérer sur une énumération
Section intitulée « Itérer sur une énumération »Une énumération est itérable dans l'ordre de déclaration. Cette propriété est précieuse pour remplir un menu déroulant, générer une documentation ou construire une liste de choix dans un formulaire.
for statut in Statut: print(statut.name, "->", statut.value)BROUILLON -> brouillonPUBLIE -> publieARCHIVE -> archiveLe dictionnaire spécial __members__ expose la correspondance nom vers membre, et une simple compréhension de liste extrait toutes les valeurs. Ces deux formes couvrent la quasi-totalité des besoins de parcours.
print([s.value for s in Statut]) # ['brouillon', 'publie', 'archive']print(list(Statut.__members__)) # ['BROUILLON', 'PUBLIE', 'ARCHIVE']Générer les valeurs avec auto()
Section intitulée « Générer les valeurs avec auto() »Quand la valeur exacte des membres n'a pas d'importance et que seul leur nom compte, écrire 1, 2, 3 à la main est fastidieux et source d'erreurs. La fonction auto() attribue automatiquement une valeur entière croissante à partir de 1.
from enum import Enum, auto
class Priorite(Enum): BASSE = auto() MOYENNE = auto() HAUTE = auto()
for p in Priorite: print(p.name, p.value)BASSE 1MOYENNE 2HAUTE 3Utilisez auto() lorsque les valeurs sont un détail d'implémentation. Si au contraire la valeur porte un sens métier (un code HTTP, un libellé stocké en base), écrivez-la explicitement pour ne pas dépendre de l'ordre des lignes.
Garantir l'unicité avec @unique
Section intitulée « Garantir l'unicité avec @unique »Par défaut, Python autorise plusieurs noms pour une même valeur : le second devient un alias du premier. C'est parfois voulu, mais souvent c'est un bug de copier-coller. Le décorateur @unique interdit ce cas et lève une erreur au chargement du module, donc avant l'exécution du reste du programme.
from enum import Enum, unique
@uniqueclass Feu(Enum): ROUGE = 1 ORANGE = 2 VERT = 3Si deux membres partagent une valeur sous @unique, l'import échoue avec un message explicite. Cette vérification précoce évite qu'un doublon silencieux ne se propage.
@uniqueclass FeuCasse(Enum): ROUGE = 1 STOP = 1 # meme valeur que ROUGE# ValueError: duplicate values found in <enum 'FeuCasse'>: STOP -> ROUGEIntEnum : une énumération qui est aussi un entier
Section intitulée « IntEnum : une énumération qui est aussi un entier »Une classe qui hérite de IntEnum produit des membres qui sont des entiers à part entière. Ils s'additionnent, se comparent et se trient comme des int, tout en gardant un nom lisible. C'est le bon choix pour des codes HTTP, des codes de sortie ou tout ce qui doit rester numériquement compatible avec du code existant.
from enum import IntEnum
class CodeHTTP(IntEnum): OK = 200 NON_TROUVE = 404 ERREUR_SERVEUR = 500
print(CodeHTTP.OK == 200) # Trueprint(CodeHTTP.ERREUR_SERVEUR >= 500) # Trueprint(sorted([CodeHTTP.ERREUR_SERVEUR, CodeHTTP.OK, CodeHTTP.NON_TROUVE]))[<CodeHTTP.OK: 200>, <CodeHTTP.NON_TROUVE: 404>, <CodeHTTP.ERREUR_SERVEUR: 500>]La contrepartie de cette souplesse est une frontière de type plus floue : un IntEnum se compare sans broncher à n'importe quel entier. Sur une énumération classique, Statut.PUBLIE == 1 renvoie False sans erreur, ce qui protège mieux contre les confusions. Réservez IntEnum aux cas où la compatibilité numérique est réellement utile.
Flag et IntFlag : combiner des options par bits
Section intitulée « Flag et IntFlag : combiner des options par bits »Les classes Flag et IntFlag sont conçues pour des membres que l'on combine, à la manière des permissions d'un fichier Linux. Chaque membre reçoit une puissance de deux (via auto()), ce qui permet de les assembler avec l'opérateur OU binaire | et de tester leur présence avec le ET binaire & ou l'opérateur in.
from enum import Flag, auto
class Permission(Flag): LECTURE = auto() ECRITURE = auto() EXECUTION = auto()
acces = Permission.LECTURE | Permission.ECRITUREprint(acces) # Permission.LECTURE|ECRITUREprint(Permission.ECRITURE in acces) # Trueprint(Permission.EXECUTION in acces) # Falseprint(bool(acces & Permission.LECTURE)) # TrueUne combinaison de Flag reste itérable : la parcourir énumère les membres réellement activés, ce qui simplifie l'affichage ou la journalisation d'un ensemble de droits.
for perm in acces: print("actif:", perm.name)actif: LECTUREactif: ECRITURELa variante IntFlag ajoute la compatibilité entière : la combinaison se convertit en int et expose sa valeur numérique, utile quand un masque de bits doit voyager vers une API ou un système externe.
from enum import IntFlag
class Options(IntFlag): NONE = 0 VERBEUX = 1 COULEUR = 2 FORCE = 4
combo = Options.VERBEUX | Options.FORCEprint(int(combo)) # 5print(combo) # 5StrEnum : une énumération qui est aussi une chaîne
Section intitulée « StrEnum : une énumération qui est aussi une chaîne »Depuis Python 3.11, la classe StrEnum joue pour les chaînes le rôle que IntEnum tient pour les entiers : ses membres sont des str. Ils se concatènent, se mettent en majuscules et se comparent directement à des chaînes, tout en conservant l'intérêt d'un type nommé. C'est pratique pour des noms d'environnement, des clés de configuration ou des libellés sérialisés en JSON.
from enum import StrEnum
class Environnement(StrEnum): DEV = "developpement" STAGING = "staging" PROD = "production"
print(Environnement.PROD) # productionprint(Environnement.PROD == "production") # Trueprint("prefixe-" + Environnement.DEV) # prefixe-developpementprint(Environnement.PROD.upper()) # PRODUCTIONNotez qu'un StrEnum s'affiche comme sa valeur brute (production) et non Environnement.PROD, contrairement à une Enum classique. C'est ce qui rend l'insertion dans une chaîne ou une réponse HTTP transparente.
Ajouter des méthodes et des attributs
Section intitulée « Ajouter des méthodes et des attributs »Une énumération reste une classe : elle peut porter des méthodes, des propriétés et même un constructeur __init__ pour décomposer une valeur composite en plusieurs attributs. Cela transforme l'énumération en une petite table de données comportementale, sans dépendre d'un dictionnaire externe.
L'exemple ci-dessous stocke pour chaque planète sa masse et son rayon, puis calcule la gravité de surface et le poids d'un objet à partir de ces attributs.
from enum import Enum
class Planete(Enum): MERCURE = (3.303e23, 2.4397e6) TERRE = (5.976e24, 6.37814e6)
def __init__(self, masse, rayon): self.masse = masse self.rayon = rayon
@property def gravite(self): G = 6.67300e-11 return G * self.masse / (self.rayon * self.rayon)
def poids(self, masse_kg): return masse_kg * self.gravite
print(round(Planete.TERRE.gravite, 2)) # 9.8print(round(Planete.TERRE.poids(80), 1)) # 784.2print(round(Planete.MERCURE.gravite, 2)) # 3.7Une méthode plus simple encapsule une règle métier directement sur l'énumération, ce qui évite de dupliquer des conditions un peu partout dans le code.
class Jour(Enum): LUNDI = 1 SAMEDI = 6 DIMANCHE = 7
def est_weekend(self): return self in (Jour.SAMEDI, Jour.DIMANCHE)
print(Jour.LUNDI.est_weekend()) # Falseprint(Jour.DIMANCHE.est_weekend()) # TrueQuand préférer une énumération à des constantes
Section intitulée « Quand préférer une énumération à des constantes »Le réflexe naturel du débutant est d'écrire des constantes de module (STATUT_PUBLIE = "publie") ou pire, des chaînes en dur dispersées dans le code. Une énumération apporte des garanties qu'aucune de ces approches ne fournit, et le tableau suivant résume ce que vous gagnez.
| Sans énumération | Avec énumération |
|---|---|
Faute de frappe ("publei") silencieuse | Statut["PUBLIE"] lève KeyError |
| Aucune liste des valeurs possibles | Itération native sur les membres |
| Pas de type dédié pour les annotations | def publier() -> Statut typable |
| Regroupement implicite, fragile | Un seul point de vérité, une classe |
Choisissez une énumération dès qu'un ensemble de valeurs est fermé et connu à l'avance : statuts, rôles, niveaux, codes, options. Un tel groupe gagne à être nommé, itérable et vérifié. Gardez en revanche de simples constantes pour une valeur isolée sans famille (une limite de taille, une URL de base) : les envelopper dans une énumération d'un seul membre n'apporterait rien.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- Une énumération hérite de
enum.Enum; chaque membre expose son.nameet sa.value. - Chaque membre est un singleton : comparez avec
is, accédez par valeurStatut("publie")ou par nomStatut["PUBLIE"]. - Une énumération est itérable dans l'ordre de déclaration ;
__members__liste noms et membres. auto()génère les valeurs quand elles n'ont pas de sens métier ;@uniqueinterdit les doublons dès l'import.IntEnumetStrEnumproduisent des membres qui sont desintou desstr; pratique mais typage plus lâche.FlagetIntFlagcombinent des options par bits avec|et&; une combinaison reste itérable.- Une énumération peut porter des méthodes, des propriétés et un
__init__pour des attributs multiples. - Préférez une énumération dès qu'un ensemble de valeurs est fermé et connu ; gardez des constantes pour les valeurs isolées.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Les bases de la POO en Python : comprendre les classes et les instances, socle sur lequel reposent les énumérations.
- Type hints en Python : annoter vos fonctions avec une énumération comme type de paramètre ou de retour.
- Le pattern matching (match/case) : aiguiller proprement sur les membres d'une énumération avec match.