Je n’ai jamais eu besoin d’un type exactement comme les d’Enum en Python de ma vie. Jamais eu le cas d’utilisation. Alors quand la feature est arrivé en python 3.4, cela a été un non-évènement pour moi.

Pourquoi faire ?

Je comprends parfaitement que des langages comme le C ou le Java en aient besoin. Leur syntaxe amène à ce genre de chose. Leur typage aussi. Mais Python ? Il y a tellement de manières de représenter les données, de les manipuler, de les passer.

Les enums c’étaient vraiment pour la déco à mes yeux.

Mais la fonctionnalité a fait débat. Si, si, on peut devenir tout rouge à propos d’une séquence de constantes.

Regardons un peu plus près de quoi il est question.

L’ancien statuquo

D’abord, en Python, on définit généralement les constantes ainsi :

FOO = 1 BAR = 2 DOH = 3 OYO = 4 FOO = 1 BAR = 2 DOH = 3 OYO = 4

Ce ne sont pas vraiment des constantes. Il n’y a rien qui ne puisse être réassigné en Python, même si parfois ça demande un peu de bidouillage, mais c’est une convention que les gens respectent.

Comme les modules sont des singleton, on peut facilement faire:

import module print ( module. FOO ) import module print(module.FOO)

Parfois on a besoin d’un peu plus. On veut plusieurs groupes de constantes. Alors on peut utiliser une classe.

class Stuff: FOO = 1 BAR = 2 DOH = 3 OYO = 4 class Stuff: FOO = 1 BAR = 2 DOH = 3 OYO = 4

Et on peut faire:

from module import Stuff print ( Stuff. FOO ) from module import Stuff print(Stuff.FOO)

Après, il y a toujours les variantes des gens qui veulent itérer dessus.

from module import Stuff for attr , value in Stuff. __dict__ . items ( ) : print ( attr , value ) from module import Stuff for attr, value in Stuff.__dict__.items(): print(attr, value)

Et puis il y a les gens qui veulent itérer dessus de manière ordonnée. On leur conseille généralement d’utiliser namedtuple :

from collections import namedtuple Stuff = namedtuple ( 'Stuff' , 'FOO BAR DOH OYO' ) stuff = Stuff ( * range ( 1 , 5 ) ) for val in stuff: print ( val ) from collections import namedtuple Stuff = namedtuple('Stuff', 'FOO BAR DOH OYO') stuff = Stuff(*range(1, 5)) for val in stuff: print(val)

Mais certains vont vouloir les noms avec les valeurs. Ils se tourneront peut être vers OrderedDict :

from collections import OrderedDict Stuff = OrderedDict ( ( ( 'FOO' , 1 ) , ( 'BAR' , 2 ) , ( 'DOH' , 3 ) , ( 'OYO' , 4 ) ) ) for attr , value in Stuff. items ( ) : print ( attr , value ) from collections import OrderedDict Stuff = OrderedDict((('FOO', 1), ('BAR', 2), ('DOH', 3), ('OYO', 4))) for attr, value in Stuff.items(): print(attr, value)

Mais pas d’accès direct par attribut, et il faut faire gaffe à la saisie ou quand on change les valeurs, etc.

Bref, les quelques personnes qui voulaient les enums n’étaient parfaitement satisfaites de ces solutions.

Ce que font les enums en Python

En gros, les Enums sont des classes bridées qui représentent des itérables de constantes. Chaque constante est un couple clé/valeur.

from enum import Enum class Stuff ( Enum ) : FOO = 1 BAR = 2 DOH = 3 OYO = 4 for member in Stuff: print ( member. name , member. value ) from enum import Enum class Stuff(Enum): FOO = 1 BAR = 2 DOH = 3 OYO = 4 for member in Stuff: print(member.name, member.value)

Les enums peuvent être héritées (mais de manière limitée) et implémenter un peu de logique puisque ce sont finalement des classes.

Il existe un type IntEnum pour que chaque membre soit comparable à un int directement plutôt que de voir chercher .value , qui par ailleurs peut être n’importe quel type avec Enum .

Et on a une syntaxe raccourcie:

Stuff = Enum ( 'Stuff' , 'FOO BAR DOH OYO' ) Stuff = Enum('Stuff', 'FOO BAR DOH OYO')

Bref, la feature ne fait pas grand-chose, en tout cas rien de ce qu’on ne pouvait faire avant. Mais elle a quelques avantages :

Les enums sont une forme de documentation par le code. Quand on en lit une, on sait que ça va être un groupe de valeurs de configuration.

Ca s’inspecte bien et l’affichage est clair.

C’est picklable.

Ca permet de faire des wrappers pour les langages qui eux utilisent beaucoup les enums ou des structs. Comme Python sert souvent de glue, c’est logique de vouloir un type qui matche.

On peut choisir entre des membres comparables entre enums (IntEnum) et avec les int, ou pas (Enum).

Les membres peuvent avoir des alias.

Mais tout ce temps après avoir vu les enums introduites, je n’en ai toujours pas l’usage. Jamais assez de constantes, ou alors quand j’en ai, je peux en faire des tuples ou des dicos sans avoir besoin d’un import.

Je suppose que je fais pas assez d’extensions C.

Quoiqu’il en soit généralement quand je vois des gens demander des enums, ce sont souvent pour de mauvaises raisons, pour reproduire ce qu’ils ont l’habitude d’utiliser dans un autre langage. Mais il y a vraiment peu de use cases typiquement Python pour les enums.

Allez, si vous avez quelques flags à mettre quelque part ou une API à wrapper, mettre une enum ne fera pas de mal.