Der Aufzählungstyp, der aus Python 3.4 in die Standardbibliothek eingeht, ist weiterhin praktisch

Enum wird aus Python 3.4 hinzugefügt, das im März dieses Jahres veröffentlicht wird. (Dokumentation)

Es wurde ein Backport entwickelt, der ab Python 2.4 verwendet und mit pip install enum34 installiert werden kann.

Warum willst du Enum

Bisher wurden beispielsweise Konstanten auf diese Weise definiert.

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

Diese Methode weist jedoch die folgenden Probleme auf.

Ich habe es ad hoc gelöst und hatte eine Bibliothek, aber ich möchte so viel Standardbibliothek. Jetzt, da es in der Standardbibliothek ist, verwenden wir es.

Einfache Bedienung

Wie bei namedtuple werden die Werte in der Reihenfolge von 1 zugewiesen, wenn Sie zuerst einen Modellnamen, dann eine Liste von Namen oder eine durch Leerzeichen getrennte Zeichenfolge übergeben.

Der resultierende Typ kann auf drei Arten auf das Element zugreifen: Attribut, Aufruf und Index.

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

Das Element hat Attribute namens und Wert.

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

Das Element selbst unterscheidet sich von seinem Wert. Alle Elemente sind Singletons, die gleichzeitig mit der Erstellung der Klasse erstellt werden. Sie können sie also mit "is" anstelle von "==" vergleichen.

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

Sie können auch iterieren.

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

Verwenden Sie einen beliebigen Wert

Indem Sie eine geerbte Klasse definieren, anstatt "Enum" aufzurufen, können Sie einem Element anstelle einer Seriennummer von 1 einen beliebigen Wert zuweisen.

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

Einschränkungen in Python 2

In Python 2 gibt es (grundsätzlich) keine Möglichkeit, die Reihenfolge zu nutzen, in der die Elemente einer Klasse definiert sind. Wenn Sie die Definitionsreihenfolge beim Auflisten mit der for-Anweisung beibehalten möchten, definieren Sie das Attribut __order__. Dies ist eine enum34-Erweiterung für die Python 2-Unterstützung, und das Python 3.4-Enum-Modul speichert die Definitionsreihenfolge ohne Aktion.

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

Behandle Elemente als ganze Zahlen

Manchmal ist es praktisch, wenn ein Element direkt als Ganzzahl fungiert. In diesem Fall können Sie IntEnum verwenden.

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

Tatsächlich ist dies die einzige Definition von IntEnum.

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

Auf diese Weise können Sie das Verhalten erben, das das Element haben soll.

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

Dies ist zwar praktisch, es besteht jedoch die Gefahr, dass dynamisch typisiertes Python es schwierig macht, festzustellen, ob eine Variable ein Enum-Element oder einen reinen Werttyp hat. Verwenden wir es mit Mäßigung.

etwa in

Selbst mit IntEnum bin ich mir nicht sicher, ob es einen Enum-Wert gibt, der diesem ganzzahligen Wert entspricht, wobei "in" direkt zwischen dem ganzzahligen Wert und dem Enum-Typ verwendet wird. in kann nur für dieses Element vom Typ Enum verwendet werden.

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

Sie können alles tun, indem Sie EnumMeta erben und anpassen oder eine private API direkt aufrufen, sich aber nicht so verhalten. Rufen Sie es einfach normal auf und suchen Sie nach Ausnahmen.

Wenn der Aufruf keinen Wert findet, wird "ValueError" ausgelöst. Sie können Indizes und KeyError auf die gleiche Weise verwenden, wenn Sie Elemente von einem Namen subtrahieren.

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

Als öffentliche API wird jedoch ein Wörterbuch mit dem Namen als Schlüssel und dem Element als Wert mit dem Namen "members" vorbereitet. Wenn Sie also nach Namen suchen, können Sie auch die üblichen Diktiervorgänge wie "in" und ".get ()" ausführen. Du kannst es benutzen.

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

Recommended Posts

Der Aufzählungstyp, der aus Python 3.4 in die Standardbibliothek eingeht, ist weiterhin praktisch
Zusammenfassung der Versionen der Standard-Python-Bibliothek, die jetzt auf https vom Server validiert werden
Fünf nützliche Python-Datentypen, die leicht zu vergessen sind
(Python3) Nein. OO (Verwenden Sie die Standardbibliothek?): 5 Shader
Ab Python 3.4 wird pip zum Standardinstallationsprogramm! ??
Lassen Sie Python den von der Standardeingabe eingegebenen JSON analysieren
Ich wollte die Python-Bibliothek von MATLAB verwenden
Suchen Sie den Teil 575 aus Wikipedia in Python
Ich habe versucht, die Python-Bibliothek von Ruby mit PyCall zu verwenden
Was können Sie mit den Standardstatistiken der Python-Bibliothek tun?
[Python] Ein Programm, das die häufigsten Vogeltypen findet
Übergeben Sie die OpenCV-Daten der ursprünglichen C ++ - Bibliothek an Python
Aus einem Buch, das der Programmierer lernen kann ... (Python): Finden Sie den häufigsten Wert
Importieren Sie ein Modul, das häufig beim Starten des Python-Interpreters verwendet wird
Überprüfung der Theorie, dass "Python und Swift ziemlich ähnlich sind"
Python-Standardmodul, das in der Befehlszeile verwendet werden kann