Le type Enum, qui entre dans la bibliothèque standard de Python 3.4, est toujours utile

Enum sera ajouté à partir de Python 3.4, qui sortira en mars de cette année. (Documentation)

Un backport a été développé qui peut être utilisé à partir de Python 2.4 et peut être installé avec pip install enum34.

Pourquoi tu veux enum

Jusqu'à présent, par exemple, les constantes ont été définies de cette manière.

class Spam:
    FOO = 1
    BAR = 2
    BAZ = 3

Cependant, cette méthode présente les problèmes suivants.

Je l'ai résolu ad hoc et j'avais une bibliothèque, mais je veux cette bibliothèque très standard. Maintenant qu'il est dans la bibliothèque standard, utilisons-le.

Utilisation simple

Comme pour namedtuple, si vous passez d'abord un nom de modèle, puis une liste de noms ou une chaîne séparée par des espaces, les valeurs seront attribuées dans l'ordre à partir de 1.

Le type résultant peut accéder à l'élément de trois manières: attribut, appel et indice.

>>> import enum
>>> Foo = enum.Enum("Foo", "foo bar baz")
>>> Foo.foo
<Foo.foo: 1>
>>> Foo(1)
<Foo.foo: 1>
>>> Foo["foo"]
<Foo.foo: 1>
>>> isinstance(Foo.foo, Foo)
True

L'élément a des attributs nommés et valeur.

>>> Foo.foo.value
1
>>> Foo.foo.name
'foo'

L'élément lui-même est distinct de sa valeur. Tous les éléments sont des singletons qui sont créés en même temps que la classe est créée, donc vous pouvez les comparer avec ʻisau lieu de==`.

>>> Foo.foo == 1
False
>>> Foo.foo is Foo(1) is Foo["foo"]
True
>>> Foo.foo is Foo(1)
True

Vous pouvez également itérer.

>>> for m in Foo:
...     print(m)
...
Foo.foo
Foo.bar
Foo.baz

Utilisez n'importe quelle valeur

En définissant une classe héritée au lieu d'appeler ʻEnum`, vous pouvez attribuer n'importe quelle valeur à un élément au lieu d'un numéro de série de 1.

>>> class Bar(enum.Enum):
...     foo = 'x'
...     bar = 'y'
...     baz = 'z'
...
>>> Bar.foo
<Bar.foo: 'x'>

Limitations dans Python 2

Dans Python 2, il n'y a (fondamentalement) aucun moyen de tirer parti de l'ordre dans lequel les éléments d'une classe sont définis. Si vous souhaitez conserver l'ordre des définitions lors de l'énumération avec l'instruction for, définissez l'attribut «order». Il s'agit d'une extension enum34 pour la prise en charge de Python 2, et le module enum Python 3.4 enregistre l'ordre des définitions sans aucune action.

>>> class Bar(enum.Enum):
...     __order__ = 'foo bar baz'
...     foo = 'x'
...     bar = 'y'
...     baz = 'z'
...
>>> list(Bar)
[<Bar.foo: 'x'>, <Bar.bar: 'y'>, <Bar.baz: 'z'>]

Traiter les éléments comme des entiers

Parfois, il est pratique pour un élément d'agir directement comme un entier. Dans ce cas, vous pouvez utiliser IntEnum.

>>> class Foo(enum.IntEnum):
...     foo = 1
...     bar = 3
...     baz = 5
...
>>> Foo.foo == 1
True
>>> Foo.foo + 2
3
>>> Foo.foo < Foo.bar
True

En fait, c'est la seule définition d'IntEnum.

class IntEnum(int, Enum):
    """Enum where members are also (and must be) ints"""

De cette manière, vous pouvez hériter du comportement souhaité pour l'élément.

>>> class Bar(str, enum.Enum):
...     foo = 'x'
...     bar = 'y'
...
>>> Bar.foo + Bar.bar
'xy'

Bien que cela soit pratique, il y a un risque que Python typé dynamiquement rend difficile de dire si une variable a un élément Enum ou un type valeur pure. Utilisons-le avec modération.

à propos de

Même avec IntEnum, je ne suis pas sûr s'il existe une valeur Enum qui correspond à cette valeur entière en utilisant ʻin directement entre la valeur entière et le type Enum. ʻIn ne peut être utilisé que sur son élément de type Enum.

>>> class Foo(enum.IntEnum):
...     foo = 3
...     bar = 7
...
>>> 3 in Foo
False
>>> Foo.foo in Foo
True

Vous pouvez faire n'importe quoi en héritant EnumMeta et en le personnalisant, ou en accédant directement à une API privée, mais ne vous comportez pas comme ça, appelez-le simplement normalement et vérifiez les exceptions.

Si l'appel ne trouve pas de valeur, ValueError est renvoyé. Vous pouvez utiliser des indices et KeyError de la même manière lorsque vous soustrayez des éléments d'un nom.

>>> Foo(2)
ValueError: 2 is not a valid Foo
>>> Foo['xyzzy']
KeyError: 'xyzzy'

Cependant, en tant qu'API publique, un dictionnaire avec le nom comme clé et l'élément comme valeur est préparé avec le nom «members», donc lorsque vous recherchez par nom, vous pouvez également utiliser «in» ou «.get ()» ou l'opération dict habituelle. Tu peux l'utiliser.

>>> Foo.__members__
{'foo': <Foo.foo: 3>, 'bar': <Foo.bar: 7>}
>>> Foo.__members__['foo']
<Foo.foo: 3>
>>> 'xyzzy' in Foo.__members__
False

Recommended Posts

Le type Enum, qui entre dans la bibliothèque standard de Python 3.4, est toujours utile
Récapitulatif des versions de la bibliothèque Python standard qui sont désormais validées par le serveur sur https
Cinq types de données Python utiles faciles à oublier
(Python3) Non oO (Utilisez-vous la bibliothèque standard?): 5 shaders
Depuis Python 3.4, pip devient le programme d'installation standard! ??
Demandez à python d'analyser le json entré à partir de l'entrée standard
Je voulais utiliser la bibliothèque Python de MATLAB
Trouvez la partie 575 de Wikipedia en Python
J'ai essayé d'utiliser la bibliothèque Python de Ruby avec PyCall
Ce que vous pouvez faire avec les statistiques de la bibliothèque Python standard
[Python] Un programme qui trouve les types d'oiseaux les plus courants
Transmettez les données OpenCV de la bibliothèque C ++ d'origine à Python
À partir d'un livre que le programmeur peut apprendre ... (Python): trouver la valeur la plus fréquente
Importez un module souvent utilisé lors du démarrage de l'interpréteur python
Vérification de la théorie selon laquelle "Python et Swift sont assez similaires"
Module standard Python utilisable en ligne de commande