web-dev-qa-db-fra.com

Comment comparer une chaîne avec une énumération python?

Je viens de découvrir l'existence d'une classe de base Enum dans python et j'essaie d'imaginer comment cela pourrait m'être utile.

Disons que je définis un statut de feu de circulation:

from enum import Enum, auto

class Signal(Enum):
    red = auto()
    green = auto()
    orange = auto()

Disons que je reçois des informations d'un sous-système de mon programme, sous la forme d'une chaîne représentant un nom de couleur, par exemple brain_detected_colour = "red".

Comment comparer cette chaîne à mes feux de signalisation?

Évidemment, brain_detected_colour is Signal.red Est False, car Signal.red N'est pas une chaîne.

Signal(brain_detected_colour) is Signal.red échoue avec ValueError: 'red' is not a valid Signal.

23
bli

On ne crée pas un instance d'un Enum . La syntaxe Signal(foo) est utilisée pour accéder aux membres Enum par valeur, qui ne sont pas destinés à être utilisés lorsqu'ils sont auto().

Cependant, on peut utiliser une chaîne pour accéder aux membres Enum comme on accéderait à une valeur dans un dict, en utilisant des crochets:

Signal[brain_detected_colour] is Signal.red

Une autre possibilité serait de comparer la chaîne au name d'un membre Enum:

# Bad practice:
brain_detected_colour is Signal.red.name

Mais ici, nous ne testons pas l'identité entre les membres Enum, mais comparons les chaînes, il est donc préférable d'utiliser un test d'égalité:

# Better practice:
brain_detected_colour == Signal.red.name

(La comparaison d'identité entre les chaînes a fonctionné grâce à internement des chaînes , ce qui vaut mieux ne pas être invoqué. Merci @mwchase et @Chris_Rands de m'avoir informé de cela.)

Une autre possibilité serait de définir explicitement les valeurs des membres comme leurs noms lors de la création de l'énumération:

class Signal(Enum):
    red = "red"
    green = "green"
    orange = "orange"

(Voir cette réponse pour une méthode pour automatiser cela.)

Ensuite, Signal(brain_detected_colour) is Signal.red serait valide.

30
bli

Il est possible que auto() renvoie le nom du membre enum comme valeur (qui se trouve dans la section auto des documents1:

>>> class AutoName(Enum):
...     def _generate_next_value_(name, start, count, last_values):
...         return name
...

>>> class Ordinal(AutoName):
...     NORTH = auto()
...     SOUTH = auto()
...     EAST = auto()
...     WEST = auto()
...

>>> list(Ordinal)
[<Ordinal.NORTH: 'NORTH'>, <Ordinal.SOUTH: 'SOUTH'>, <Ordinal.EAST: 'EAST'>, <Ordinal.WEST: 'WEST'>]

1 Cela nécessite la version Python 3.6 ou aenum 2.02 (aenum fonctionne avec des Pythons aussi anciens que 2.7).

2 Divulgation: je suis l'auteur du Python stdlib Enum , le enum34 backport , et la bibliothèque Advanced Enumeration (aenum) .

10
Ethan Furman