PROJET AUTOBLOG


Sam & Max: Python, Django, Git et du cul

Site original : Sam & Max: Python, Django, Git et du cul

⇐ retour index

Mise à jour

Mise à jour de la base de données, veuillez patienter...

Les enums en Python 9

dimanche 17 janvier 2016 à 20:01

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

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)

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

Et on peut faire:

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)

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')(*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)

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)

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')

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 :

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.