18 Aufzählungstypen – Enum 

Ein Aufzählungstyp ist ein Datentyp, dessen Wertebereich eine Menge von symbolischen Konstanten ist. Ein Beispiel dafür ist der (noch imaginäre) Datentyp Wochentag, dessen Instanzen jeweils einen Tag der Woche repräsentieren. Mit den bislang besprochenen Mitteln lässt sich dieser Datentyp beispielsweise als ganze Zahl oder als String umsetzen. Beide Varianten setzen eine implizit festgelegte Zuordnung von Zahlen bzw. Zeichenketten auf das abstrakte Konzept »Wochentag« voraus. Diese Zuordnung bringt einige Probleme mit sich:
- Die Operatoren der Datentypen int und str sind nach wie vor verfügbar, verlieren aber ihre Bedeutung. Es ist beispielsweise nicht klar, was »Montag geteilt durch Dienstag« bedeuten soll.
- Es findet keine Überprüfung statt, ob der einer Wochentag-Variablen zugeordnete Wert zulässig ist.
- Der Wert einer Wochentag-Variablen lässt sich mit anderen int- oder str-Instanzen ohne Wochentag-Bedeutung vergleichen. Möglicherweise noch schlimmer ist, dass sich Wochentag-Variablen mit Werten vergleichen lassen, die Instanzen anderer Aufzählungen repräsentieren, beispielsweise Ampelfarben.
- Bei Bildschirmausgaben wird nicht der Wochentag ausgegeben, sondern der intern zugeordnete Wert, im schlimmsten Fall also eine Zahl ohne jeden Bezug zum übergeordneten Konzept. Das erschwert beispielsweise das Verständnis von Debug-Ausgaben.
Seit Python 3.4 enthält die Standardbibliothek das Modul enum, das die Basisklasse Enum für unveränderliche Aufzählungstypen bereitstellt. Im folgenden Beispiel wird der bereits angesprochene Datentyp Wochentag als Aufzählungstyp implementiert.
>>> import enum
>>> class Wochentag(enum.Enum):
... Montag = 1
... Dienstag = 2
... Mittwoch = 3
... Donnerstag = 4
... Freitag = 5
... Samstag = 6
... Sonntag = 7
...
Für jeden Tag der Woche wird eine symbolische Konstante in der von Enum abgeleiteten Klasse Wochentag erstellt. Jeder Konstante wird ein interner Wert zugewiesen. Dieser Wert ist in diesem Fall eine ganze Zahl, das muss aber nicht zwingend so sein.
Ein konkreter Wochentag lässt sich jetzt über die definierte Konstante, den zugeordneten internen Wert oder seinen Namen erzeugen:
>>> Wochentag.Samstag
<Wochentag.Samstag: 6>
>>> Wochentag(6)
<Wochentag.Samstag: 6>
>>> Wochentag["Samstag"]
<Wochentag.Samstag: 6>
An diesen Beispielen sehen Sie auch, dass die Bildschirmausgabe eines Aufzählungswertes seinen symbolischen Namen beinhaltet. Auf diesen Namen kann über das Attribut name zugegriffen werden:
>>> Wochentag.Samstag.name
'Samstag'
Aufzählungswerte lassen sich nur untereinander vergleichen. Insbesondere ist auch kein Vergleich mit dem internen Wert zulässig:
>>> Wochentag.Samstag is Wochentag.Samstag
True
>>> Wochentag.Montag != Wochentag.Dienstag
True
>>> Wochentag.Montag == 1
False
Aufzählungstypen erlauben es, ihre Werte zu durchlaufen. Dabei werden eventuelle Aliasse übersprungen. Aliasse sind Aufzählungswerte, denen der gleiche interne Wert zugeordnet ist wie einem zuvor definierten Aufzählungswert.
>>> for tag in Wochentag:
... print(tag)
...
Wochentag.Montag
Wochentag.Dienstag
Wochentag.Mittwoch
Wochentag.Donnerstag
Wochentag.Freitag
Wochentag.Samstag
Wochentag.Sonntag
Seit Python 3.6 existiert die Funktion auto, mit deren Hilfe sich ein Aufzählungstyp definieren lässt, ohne konkrete interne Werte zu vergeben:
>>> class Wochentag(enum.Enum):
... Montag = enum.auto()
... Dienstag = enum.auto()
... Mittwoch = enum.auto()
... Donnerstag = enum.auto()
... Freitag = enum.auto()
... Samstag = enum.auto()
... Sonntag = enum.auto()
...
>>> Wochentag.Montag
<Wochentag.Montag: 1>
18.1 Aufzählungstyp für Bitmuster – Flag 

Mit Python 3.6 wurde der Aufzählungstyp Flag eingeführt, der die internen Werte so definiert, dass die symbolischen Konstanten mithilfe bitweiser Operatoren miteinander kombiniert werden können. Dies wird anhand des folgenden Beispiels deutlich, in dem der Zustand einer Ampelanlage durch eine Kombination symbolischer Konstanten abgebildet wird:
>>> class Ampel(enum.Flag):
... Rot = enum.auto()
... Gelb = enum.auto()
... Gruen = enum.auto()
...
Mithilfe des bitweisen ODER können zwei symbolische Konstanten, auch Flags genannt, miteinander kombiniert werden:
>>> kombinierter_zustand = Ampel.Rot | Ampel.Gelb
In unserem Beispiel würde kombinierter_zustand eine Ampel beschreiben, bei der aktuell die rote und die gelbe Lampe gemeinsam leuchten.
Das bitweise UND kann verwendet werden, um zu überprüfen, ob eine symbolische Konstante in einer Kombination enthalten ist:
>>> kombinierter_zustand & Ampel.Rot
<Ampel.Rot: 1>
>>> kombinierter_zustand & Ampel.Gruen
<Ampel.0: 0>
Das Ergebnis des bitweisen UND kann als Wahrheitswert interpretiert werden:
>>> bool(kombinierter_zustand & Ampel.Rot)
True
>>> bool(kombinierter_zustand & Ampel.Gruen)
False