22. enum

Enum, IntEnum, StrEnum, Flag, auto(), @unique, méthodes et itération.


22.1 Enum de base

from enum import Enum
 
class Couleur(Enum):
    ROUGE = 1
    VERT = 2
    BLEU = 3

Accès :

Couleur.ROUGE          # Couleur.ROUGE
Couleur(1)             # Couleur.ROUGE (par valeur)
Couleur["ROUGE"]       # Couleur.ROUGE (par nom)
Couleur.ROUGE.name     # "ROUGE"
Couleur.ROUGE.value    # 1
isinstance(Couleur.ROUGE, Couleur)  # True

Comparaison :

Couleur.ROUGE is Couleur.ROUGE      # True (singleton)
Couleur.ROUGE == Couleur.ROUGE      # True (par identité)
Couleur.ROUGE == 1                  # False (pas de comparaison avec int)
Couleur.ROUGE in Couleur            # True

22.2 auto() — valeurs automatiques

from enum import Enum, auto
 
class Couleur(Enum):
    ROUGE = auto()   # 1
    VERT = auto()    # 2
    BLEU = auto()    # 3

Surcharger _generate_next_value_ :

class Couleur(Enum):
    def _generate_next_value_(name, start, count, last_values):
        return name.lower()
 
    ROUGE = auto()   # "rouge"
    VERT = auto()    # "vert"

22.3 @unique — valeurs uniques garanties

from enum import Enum, unique
 
@unique
class Status(Enum):
    OK = 200
    NOT_FOUND = 404
    ERROR = 500
    # DUPLICATE = 200  # ValueError: duplicate values

22.4 IntEnum — membre = int

from enum import IntEnum
 
class StatusHTTP(IntEnum):
    OK = 200
    NOT_FOUND = 404
 
StatusHTTP.OK == 200          # True
StatusHTTP.OK < 300           # True (comportement int)
int(StatusHTTP.OK)            # 200

Cas d’usage : remplacer les constantes entières nommées.

22.5 StrEnum (3.11+)

from enum import StrEnum
 
class Mode(StrEnum):
    TRAIN = "train"
    EVAL = "eval"
    PREDICT = "predict"
 
Mode.TRAIN == "train"         # True
str(Mode.TRAIN)               # "train"
", ".join(Mode)               # "train, eval, predict"

22.6 Flag — combinaisons de bits

from enum import Flag, auto
 
class Permission(Flag):
    LECTURE = auto()      # 0b001
    ÉCRITURE = auto()     # 0b010
    EXÉCUTION = auto()    # 0b100
 
# Combinaisons
perm = Permission.LECTURE | Permission.ÉCRITURE
Permission.LECTURE in perm            # True
Permission.EXÉCUTION in perm          # False
 
perm |= Permission.EXÉCUTION          # ajouter
perm &= ~Permission.LECTURE           # retirer
perm ^= Permission.ÉCRITURE           # basculer
 
perm.name               # "LECTURE|ÉCRITURE|EXÉCUTION"
perm.value              # 7
 
# Membres composés
class Permission(Flag):
    LECTURE = auto()
    ÉCRITURE = auto()
    EXÉCUTION = auto()
    TOUT = LECTURE | ÉCRITURE | EXÉCUTION
    AUCUNE = 0
 
Permission.TOUT in Permission  # False (c'est une combinaison, pas un membre simple)

22.7 Flag avec valeurs explicites

class Drapeau(Flag):
    A = 0b0001
    B = 0b0010
    C = 0b0100
    D = 0b1000
    AB = A | B  # combinaison nommée

22.8 Itération et méthodes

# Lister tous les membres
list(Couleur)           # [Couleur.ROUGE, Couleur.VERT, Couleur.BLEU]
len(Couleur)            # 3
 
# Itération
for c in Couleur:
    print(c.name, c.value)
 
# Membres dict
Couleur.__members__
# {'ROUGE': <Couleur.ROUGE: 1>, 'VERT': <Couleur.VERT: 2>, ...}

22.9 Méthodes et propriétés sur un Enum

class Status(Enum):
    OK = 200
    NOT_FOUND = 404
    ERROR = 500
 
    @property
    def est_erreur(self) -> bool:
        return self.value >= 400
 
    def description(self) -> str:
        descriptions = {
            200: "Succès",
            404: "Non trouvé",
            500: "Erreur interne",
        }
        return descriptions.get(self.value, "Inconnu")
 
Status.OK.description()       # "Succès"
Status.NOT_FOUND.est_erreur   # True

22.10 Héritage entre enums

class Base(Enum):
    A = 1
    B = 2
 
class Étendu(Base):
    C = 3  # OK si Base n'a pas de méthode ni de valeur en conflit
 
# Attention : les enums avec des membres ne peuvent pas hériter d'enums
# avec des membres (sauf s'ils sont vides ou avec mixin)

22.11 Mixin avec Enum

class MonIntEnum(int, Enum):
    """Mixin : les membres sont aussi des int."""
    A = 1
    B = 2
 
MonIntEnum.A + MonIntEnum.B  # 3

22.12 Enum vs constantes

# Sans Enum (constantes nues)
STATUS_OK = 200
STATUS_NOT_FOUND = 404
 
def gérer(status):
    if status == STATUS_OK:
        ...
 
# Avec Enum — typé, groupé, auto-documenté
class Status(IntEnum):
    OK = 200
    NOT_FOUND = 404
 
def gérer(status: Status):
    if status == Status.OK:
        ...

Avantages :

  • Namespace : Couleur.ROUGE vs ROUGE nu
  • Typage : def f(c: Couleur) — intention claire
  • Valeurs garanties uniques (avec @unique)
  • Itérable, sérialisable, in check
  • IntEnum compatible avec les constantes entières

22.13 Bonnes pratiques

  • Utiliser auto() quand les valeurs exactes n’importent pas
  • @unique pour éviter les doublons accidentels
  • IntEnum pour remplacer des constantes entières
  • StrEnum (3.11+) pour remplacer des constantes chaînes
  • Flag pour les combinaisons de bits (permissions, options)
  • Les enums sont des singletons — utiliser is pour comparer si possible

🔗 ← Retour au cours · ← précédent · Suivant →