Enum HOWTO¶
Eine Enum ist eine Menge von symbolischen Namen, die eindeutigen Werten zugeordnet sind. Sie sind ähnlich wie globale Variablen, bieten jedoch eine nützlichere repr(), Gruppierung, Typsicherheit und einige andere Funktionen.
Sie sind am nützlichsten, wenn Sie eine Variable haben, die einen von einer begrenzten Auswahl von Werten annehmen kann. Zum Beispiel die Wochentage
>>> from enum import Enum
>>> class Weekday(Enum):
... MONDAY = 1
... TUESDAY = 2
... WEDNESDAY = 3
... THURSDAY = 4
... FRIDAY = 5
... SATURDAY = 6
... SUNDAY = 7
Oder vielleicht die RGB-Primärfarben
>>> from enum import Enum
>>> class Color(Enum):
... RED = 1
... GREEN = 2
... BLUE = 3
Wie Sie sehen können, ist das Erstellen einer Enum so einfach wie das Schreiben einer Klasse, die selbst von Enum erbt.
Hinweis
Groß-/Kleinschreibung von Enum-Mitgliedern
Da Enums zur Darstellung von Konstanten verwendet werden und um Probleme mit Namenskonflikten zwischen Mixin-Klassenmethoden/-Attributen und Enum-Namen zu vermeiden, empfehlen wir dringend die Verwendung von GROSSBUCHSTABEN für Mitgliedernamen und werden diesen Stil in unseren Beispielen verwenden.
Abhängig von der Art des Enums ist der Wert eines Mitglieds möglicherweise wichtig oder auch nicht, aber auf jeden Fall kann dieser Wert verwendet werden, um das entsprechende Mitglied abzurufen
>>> Weekday(3)
<Weekday.WEDNESDAY: 3>
Wie Sie sehen können, zeigt die repr() eines Mitglieds den Enum-Namen, den Mitgliedernamen und den Wert an. Die str() eines Mitglieds zeigt nur den Enum-Namen und den Mitgliedernamen an.
>>> print(Weekday.THURSDAY)
Weekday.THURSDAY
Der Typ eines Enumerationsmitglieds ist das Enum, zu dem es gehört.
>>> type(Weekday.MONDAY)
<enum 'Weekday'>
>>> isinstance(Weekday.FRIDAY, Weekday)
True
Enum-Mitglieder haben ein Attribut, das nur ihren name enthält.
>>> print(Weekday.TUESDAY.name)
TUESDAY
Ebenso haben sie ein Attribut für ihren value.
>>> Weekday.WEDNESDAY.value
3
Im Gegensatz zu vielen Sprachen, die Enumerationen ausschließlich als Namens-/Wertpaare behandeln, können Python Enums Verhalten hinzugefügt werden. Beispielsweise hat datetime.date zwei Methoden, um den Wochentag zurückzugeben: weekday() und isoweekday(). Der Unterschied besteht darin, dass eine von ihnen von 0-6 zählt und die andere von 1-7. Anstatt dies selbst zu verfolgen, können wir eine Methode zum Weekday-Enum hinzufügen, um den Tag aus der date-Instanz zu extrahieren und das passende Enum-Mitglied zurückzugeben.
@classmethod
def from_date(cls, date):
return cls(date.isoweekday())
Das vollständige Weekday-Enum sieht nun so aus:
>>> class Weekday(Enum):
... MONDAY = 1
... TUESDAY = 2
... WEDNESDAY = 3
... THURSDAY = 4
... FRIDAY = 5
... SATURDAY = 6
... SUNDAY = 7
... #
... @classmethod
... def from_date(cls, date):
... return cls(date.isoweekday())
Jetzt können wir herausfinden, welcher Tag heute ist! Beachten Sie:
>>> from datetime import date
>>> Weekday.from_date(date.today())
<Weekday.TUESDAY: 2>
Natürlich sehen Sie, wenn Sie dies an einem anderen Tag lesen, diesen Tag stattdessen.
Dieses Weekday-Enum ist großartig, wenn unsere Variable nur einen Tag benötigt, aber was ist, wenn wir mehrere benötigen? Vielleicht schreiben wir eine Funktion zum Plotten von Aufgaben während einer Woche und möchten keine Liste verwenden – wir könnten einen anderen Typ von Enum verwenden.
>>> from enum import Flag
>>> class Weekday(Flag):
... MONDAY = 1
... TUESDAY = 2
... WEDNESDAY = 4
... THURSDAY = 8
... FRIDAY = 16
... SATURDAY = 32
... SUNDAY = 64
Wir haben zwei Dinge geändert: Wir erben von Flag, und die Werte sind alles Potenzen von 2.
Genau wie das ursprüngliche Weekday-Enum oben, können wir eine einzelne Auswahl haben.
>>> first_week_day = Weekday.MONDAY
>>> first_week_day
<Weekday.MONDAY: 1>
Aber Flag erlaubt es uns auch, mehrere Mitglieder zu einer einzigen Variablen zu kombinieren.
>>> weekend = Weekday.SATURDAY | Weekday.SUNDAY
>>> weekend
<Weekday.SATURDAY|SUNDAY: 96>
Sie können sogar über eine Flag-Variable iterieren.
>>> for day in weekend:
... print(day)
Weekday.SATURDAY
Weekday.SUNDAY
Okay, richten wir ein paar Aufgaben ein.
>>> chores_for_ethan = {
... 'feed the cat': Weekday.MONDAY | Weekday.WEDNESDAY | Weekday.FRIDAY,
... 'do the dishes': Weekday.TUESDAY | Weekday.THURSDAY,
... 'answer SO questions': Weekday.SATURDAY,
... }
Und eine Funktion zur Anzeige der Aufgaben für einen bestimmten Tag.
>>> def show_chores(chores, day):
... for chore, days in chores.items():
... if day in days:
... print(chore)
...
>>> show_chores(chores_for_ethan, Weekday.SATURDAY)
answer SO questions
In Fällen, in denen die tatsächlichen Werte der Mitglieder keine Rolle spielen, können Sie sich etwas Arbeit sparen und auto() für die Werte verwenden.
>>> from enum import auto
>>> class Weekday(Flag):
... MONDAY = auto()
... TUESDAY = auto()
... WEDNESDAY = auto()
... THURSDAY = auto()
... FRIDAY = auto()
... SATURDAY = auto()
... SUNDAY = auto()
... WEEKEND = SATURDAY | SUNDAY
Programmatischer Zugriff auf Enumerationsmitglieder und ihre Attribute¶
Manchmal ist es nützlich, auf Mitglieder in Enumerationen programmatisch zuzugreifen (d. h. Situationen, in denen Color.RED nicht ausreicht, da die genaue Farbe zur Programm-Schreibzeit nicht bekannt ist). Enum ermöglicht einen solchen Zugriff.
>>> Color(1)
<Color.RED: 1>
>>> Color(3)
<Color.BLUE: 3>
Wenn Sie per Name auf Enum-Mitglieder zugreifen möchten, verwenden Sie den Elementzugriff.
>>> Color['RED']
<Color.RED: 1>
>>> Color['GREEN']
<Color.GREEN: 2>
Wenn Sie ein Enum-Mitglied haben und dessen name oder value benötigen.
>>> member = Color.RED
>>> member.name
'RED'
>>> member.value
1
Duplizieren von Enum-Mitgliedern und -Werten¶
Zwei Enum-Mitglieder mit demselben Namen sind ungültig.
>>> class Shape(Enum):
... SQUARE = 2
... SQUARE = 3
...
Traceback (most recent call last):
...
TypeError: 'SQUARE' already defined as 2
Ein Enum-Mitglied kann jedoch andere Namen haben. Bei zwei Einträgen A und B mit demselben Wert (und A zuerst definiert) ist B ein Alias für das Mitglied A. Ein Lookup nach Wert des Werts von A gibt das Mitglied A zurück. Ein Lookup nach Namen von A gibt das Mitglied A zurück. Ein Lookup nach Namen von B gibt ebenfalls das Mitglied A zurück.
>>> class Shape(Enum):
... SQUARE = 2
... DIAMOND = 1
... CIRCLE = 3
... ALIAS_FOR_SQUARE = 2
...
>>> Shape.SQUARE
<Shape.SQUARE: 2>
>>> Shape.ALIAS_FOR_SQUARE
<Shape.SQUARE: 2>
>>> Shape(2)
<Shape.SQUARE: 2>
Hinweis
Der Versuch, ein Mitglied mit demselben Namen wie ein bereits definiertes Attribut (ein anderes Mitglied, eine Methode usw.) zu erstellen, oder der Versuch, ein Attribut mit demselben Namen wie ein Mitglied zu erstellen, ist nicht erlaubt.
Sicherstellen eindeutiger Enumerationswerte¶
Standardmäßig erlauben Enumerationen mehrere Namen als Aliase für denselben Wert. Wenn dieses Verhalten nicht erwünscht ist, können Sie den Dekorator unique() verwenden.
>>> from enum import Enum, unique
>>> @unique
... class Mistake(Enum):
... ONE = 1
... TWO = 2
... THREE = 3
... FOUR = 3
...
Traceback (most recent call last):
...
ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE
Verwenden automatischer Werte¶
Wenn der genaue Wert unwichtig ist, können Sie auto verwenden.
>>> from enum import Enum, auto
>>> class Color(Enum):
... RED = auto()
... BLUE = auto()
... GREEN = auto()
...
>>> [member.value for member in Color]
[1, 2, 3]
Die Werte werden von _generate_next_value_() gewählt, die überschrieben werden kann.
>>> class AutoName(Enum):
... @staticmethod
... def _generate_next_value_(name, start, count, last_values):
... return name
...
>>> class Ordinal(AutoName):
... NORTH = auto()
... SOUTH = auto()
... EAST = auto()
... WEST = auto()
...
>>> [member.value for member in Ordinal]
['NORTH', 'SOUTH', 'EAST', 'WEST']
Hinweis
Die Methode _generate_next_value_() muss vor allen Mitgliedern definiert werden.
Iteration¶
Das Iterieren über die Mitglieder eines Enums liefert nicht die Aliase.
>>> list(Shape)
[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
>>> list(Weekday)
[<Weekday.MONDAY: 1>, <Weekday.TUESDAY: 2>, <Weekday.WEDNESDAY: 4>, <Weekday.THURSDAY: 8>, <Weekday.FRIDAY: 16>, <Weekday.SATURDAY: 32>, <Weekday.SUNDAY: 64>]
Beachten Sie, dass die Aliase Shape.ALIAS_FOR_SQUARE und Weekday.WEEKEND nicht angezeigt werden.
Das spezielle Attribut __members__ ist eine schreibgeschützte geordnete Abbildung von Namen zu Mitgliedern. Es enthält alle in der Enumeration definierten Namen, einschließlich der Aliase.
>>> for name, member in Shape.__members__.items():
... name, member
...
('SQUARE', <Shape.SQUARE: 2>)
('DIAMOND', <Shape.DIAMOND: 1>)
('CIRCLE', <Shape.CIRCLE: 3>)
('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)
Das Attribut __members__ kann für detaillierten programmatischen Zugriff auf die Enumerationsmitglieder verwendet werden. Zum Beispiel das Finden aller Aliase.
>>> [name for name, member in Shape.__members__.items() if member.name != name]
['ALIAS_FOR_SQUARE']
Hinweis
Aliase für Flags umfassen Mitglieder mit mehreren gesetzten Flags, wie z. B. 3, und keine gesetzten Flags, d. h. 0.
Vergleiche¶
Enumerationsmitglieder werden nach Identität verglichen.
>>> Color.RED is Color.RED
True
>>> Color.RED is Color.BLUE
False
>>> Color.RED is not Color.BLUE
True
Geordnete Vergleiche zwischen Enumerationswerten werden nicht unterstützt. Enum-Mitglieder sind keine ganzen Zahlen (aber siehe IntEnum unten).
>>> Color.RED < Color.BLUE
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'Color' and 'Color'
Gleichheitsvergleiche sind jedoch definiert.
>>> Color.BLUE == Color.RED
False
>>> Color.BLUE != Color.RED
True
>>> Color.BLUE == Color.BLUE
True
Vergleiche mit Nicht-Enumerationswerten sind immer ungleich (auch hier wurde IntEnum ausdrücklich anders konzipiert, siehe unten).
>>> Color.BLUE == 2
False
Warnung
Es ist möglich, Module neu zu laden – wenn ein neu geladenes Modul Enums enthält, werden diese neu erstellt und die neuen Mitglieder vergleichen sich möglicherweise nicht identisch/gleich mit den ursprünglichen Mitgliedern.
Zugelassene Mitglieder und Attribute von Enumerationen¶
Die meisten der obigen Beispiele verwenden ganze Zahlen für Enumerationswerte. Die Verwendung von ganzen Zahlen ist kurz und praktisch (und wird standardmäßig von der Funktionalen API bereitgestellt), ist aber nicht strikt durchgesetzt. In den allermeisten Anwendungsfällen kümmert man sich nicht darum, was der tatsächliche Wert einer Enumeration ist. Aber wenn der Wert wichtig ist, können Enumerationen beliebige Werte haben.
Enumerationen sind Python-Klassen und können wie üblich Methoden und spezielle Methoden haben. Wenn wir diese Enumeration haben:
>>> class Mood(Enum):
... FUNKY = 1
... HAPPY = 3
...
... def describe(self):
... # self is the member here
... return self.name, self.value
...
... def __str__(self):
... return 'my custom str! {0}'.format(self.value)
...
... @classmethod
... def favorite_mood(cls):
... # cls here is the enumeration
... return cls.HAPPY
...
Dann
>>> Mood.favorite_mood()
<Mood.HAPPY: 3>
>>> Mood.HAPPY.describe()
('HAPPY', 3)
>>> str(Mood.FUNKY)
'my custom str! 1'
Die Regeln für das, was erlaubt ist, sind wie folgt: Namen, die mit einem einzelnen Unterstrich beginnen und enden, sind von enum reserviert und dürfen nicht verwendet werden; alle anderen Attribute, die innerhalb einer Enumeration definiert sind, werden zu Mitgliedern dieser Enumeration, mit Ausnahme von speziellen Methoden (__str__(), __add__() usw.), Deskriptoren (Methoden sind ebenfalls Deskriptoren) und Variablennamen, die in _ignore_ aufgeführt sind.
Hinweis: Wenn Ihre Enumeration __new__() und/oder __init__() definiert, werden alle für das Enum-Mitglied angegebenen Werte an diese Methoden übergeben. Siehe Planet für ein Beispiel.
Hinweis
Die Methode __new__(), falls definiert, wird während der Erstellung der Enum-Mitglieder verwendet; sie wird dann durch die __new__() von Enum ersetzt, die nach der Klassenbildung zur Suche nach vorhandenen Mitgliedern verwendet wird. Siehe Wann __new__() vs. __init__() verwenden für weitere Details.
Eingeschränkte Enum-Unterklassenbildung¶
Eine neue Enum-Klasse muss eine Basis-Enum-Klasse, bis zu einen konkreten Datentyp und beliebig viele object-basierte Mixin-Klassen haben. Die Reihenfolge dieser Basisklassen ist:
class EnumName([mix-in, ...,] [data-type,] base-enum):
pass
Außerdem ist die Unterklassenbildung einer Enumeration nur dann erlaubt, wenn die Enumeration keine Mitglieder definiert. Dies ist also verboten:
>>> class MoreColor(Color):
... PINK = 17
...
Traceback (most recent call last):
...
TypeError: <enum 'MoreColor'> cannot extend <enum 'Color'>
Aber dies ist erlaubt:
>>> class Foo(Enum):
... def some_behavior(self):
... pass
...
>>> class Bar(Foo):
... HAPPY = 1
... SAD = 2
...
Die Unterklassenbildung von Enums, die Mitglieder definieren, würde zu einer Verletzung einiger wichtiger Invarianten von Typen und Instanzen führen. Andererseits ist es sinnvoll, ein gemeinsames Verhalten zwischen einer Gruppe von Enumerationen zu ermöglichen. (Siehe OrderedEnum für ein Beispiel.)
Dataclass-Unterstützung¶
Beim Erben von einer dataclass lässt die __repr__() den Namen der geerbten Klasse aus. Zum Beispiel:
>>> from dataclasses import dataclass, field
>>> @dataclass
... class CreatureDataMixin:
... size: str
... legs: int
... tail: bool = field(repr=False, default=True)
...
>>> class Creature(CreatureDataMixin, Enum):
... BEETLE = 'small', 6
... DOG = 'medium', 4
...
>>> Creature.DOG
<Creature.DOG: size='medium', legs=4>
Verwenden Sie das dataclass()-Argument repr=False, um die Standard-repr() zu verwenden.
Geändert in Version 3.12: Nur die Dataclass-Felder werden im Wertebereich angezeigt, nicht der Name der Dataclass.
Hinweis
Das Hinzufügen des Dekorators dataclass() zu Enum und seinen Unterklassen wird nicht unterstützt. Es wird keine Fehler auslösen, aber es wird sehr seltsame Ergebnisse zur Laufzeit liefern, z. B. dass Mitglieder gleich zueinander sind.
>>> @dataclass # don't do this: it does not make any sense
... class Color(Enum):
... RED = 1
... BLUE = 2
...
>>> Color.RED is Color.BLUE
False
>>> Color.RED == Color.BLUE # problem is here: they should not be equal
True
Pickling¶
Enumerationen können gepickelt und entpickelt werden.
>>> from test.test_enum import Fruit
>>> from pickle import dumps, loads
>>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
True
Die üblichen Einschränkungen für das Pickling gelten: pickelbare Enums müssen im obersten Level eines Moduls definiert sein, da das Entpickeln erfordert, dass sie aus diesem Modul importierbar sind.
Hinweis
Mit Pickle-Protokollversion 4 ist es möglich, Enums, die in andere Klassen verschachtelt sind, einfach zu pickeln.
Es ist möglich zu ändern, wie Enum-Mitglieder gepickelt/entpickelt werden, indem __reduce_ex__() in der Enumerationsklasse definiert wird. Die Standardmethode ist per Wert, aber Enums mit komplizierten Werten möchten möglicherweise per Namen verwenden.
>>> import enum
>>> class MyEnum(enum.Enum):
... __reduce_ex__ = enum.pickle_by_enum_name
Hinweis
Die Verwendung per Name für Flags wird nicht empfohlen, da unbenannte Aliase nicht entpickelt werden.
Funktionale API¶
Die Klasse Enum ist aufrufbar und bietet die folgende funktionale API.
>>> Animal = Enum('Animal', 'ANT BEE CAT DOG')
>>> Animal
<enum 'Animal'>
>>> Animal.ANT
<Animal.ANT: 1>
>>> list(Animal)
[<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]
Die Semantik dieser API ähnelt der von namedtuple. Das erste Argument des Aufrufs von Enum ist der Name der Enumeration.
Das zweite Argument ist die Quelle der Enumerationsmitgliedernamen. Es kann eine durch Leerzeichen getrennte Zeichenkette von Namen, eine Sequenz von Namen, eine Sequenz von 2-Tupeln mit Schlüssel/Wert-Paaren oder eine Zuordnung (z. B. ein Dictionary) von Namen zu Werten sein. Die letzten beiden Optionen ermöglichen die Zuweisung beliebiger Werte zu Enumerationen; die anderen weisen automatisch aufsteigende ganze Zahlen beginnend mit 1 zu (verwenden Sie den Parameter start, um einen anderen Startwert anzugeben). Eine neue Klasse, die von Enum abgeleitet ist, wird zurückgegeben. Mit anderen Worten, die obige Zuweisung zu Animal ist äquivalent zu:
>>> class Animal(Enum):
... ANT = 1
... BEE = 2
... CAT = 3
... DOG = 4
...
Der Grund für die Standardeinstellung auf 1 als Startnummer und nicht auf 0 ist, dass 0 im booleschen Sinne False ist, aber standardmäßig alle Enum-Mitglieder zu True ausgewertet werden.
Das Pickeln von Enums, die mit der funktionalen API erstellt wurden, kann knifflig sein, da Details der Frame-Stack-Implementierung verwendet werden, um zu versuchen, herauszufinden, in welchem Modul die Enumeration erstellt wird (z. B. schlägt dies fehl, wenn Sie eine Hilfsfunktion in einem separaten Modul verwenden, und funktioniert möglicherweise auch nicht auf IronPython oder Jython). Die Lösung besteht darin, den Modulnamen explizit wie folgt anzugeben:
>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)
Warnung
Wenn module nicht angegeben ist und Enum nicht feststellen kann, was es ist, werden die neuen Enum-Mitglieder nicht entpickelbar sein; um Fehler näher an der Quelle zu halten, wird das Pickling deaktiviert.
Das neue Pickle-Protokoll 4 hängt auch unter bestimmten Umständen davon ab, dass __qualname__ auf den Speicherort gesetzt wird, an dem Pickle die Klasse finden kann. Zum Beispiel, wenn die Klasse in class SomeData im globalen Geltungsbereich verfügbar gemacht wurde:
>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')
Die vollständige Signatur ist:
Enum(
value='NewEnumName',
names=<...>,
*,
module='...',
qualname='...',
type=<mixed-in class>,
start=1,
)
value: Was die neue Enum-Klasse als ihren Namen aufzeichnen wird.
names: Die Enum-Mitglieder. Dies kann eine durch Leerzeichen oder Kommas getrennte Zeichenkette sein (Werte beginnen bei 1, sofern nicht anders angegeben).
'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'
oder ein Iterator von Namen
['RED', 'GREEN', 'BLUE']
oder ein Iterator von (Name, Wert)-Paaren
[('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]
oder eine Zuordnung
{'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}
module: Name des Moduls, in dem die neue Enum-Klasse zu finden ist.
qualname: Wo im Modul die neue Enum-Klasse zu finden ist.
type: Typ, der in die neue Enum-Klasse gemischt werden soll.
start: Zahl, mit der gezählt werden soll, wenn nur Namen übergeben werden.
Geändert in Version 3.5: Der Parameter start wurde hinzugefügt.
Abgeleitete Enumerationen¶
IntEnum¶
Die erste Variante von Enum, die bereitgestellt wird, ist auch eine Unterklasse von int. Mitglieder einer IntEnum können mit ganzen Zahlen verglichen werden; folglich können auch ganzzahlige Enumerationen unterschiedlicher Typen miteinander verglichen werden.
>>> from enum import IntEnum
>>> class Shape(IntEnum):
... CIRCLE = 1
... SQUARE = 2
...
>>> class Request(IntEnum):
... POST = 1
... GET = 2
...
>>> Shape == 1
False
>>> Shape.CIRCLE == 1
True
>>> Shape.CIRCLE == Request.POST
True
Sie können jedoch immer noch nicht mit Standard-Enum-Enumerationen verglichen werden.
>>> class Shape(IntEnum):
... CIRCLE = 1
... SQUARE = 2
...
>>> class Color(Enum):
... RED = 1
... GREEN = 2
...
>>> Shape.CIRCLE == Color.RED
False
IntEnum-Werte verhalten sich in anderer Hinsicht wie ganze Zahlen, wie Sie es erwarten würden.
>>> int(Shape.CIRCLE)
1
>>> ['a', 'b', 'c'][Shape.CIRCLE]
'b'
>>> [i for i in range(Shape.SQUARE)]
[0, 1]
StrEnum¶
Die zweite Variante von Enum, die bereitgestellt wird, ist auch eine Unterklasse von str. Mitglieder einer StrEnum können mit Zeichenketten verglichen werden; folglich können auch Zeichenketten-Enumerationen unterschiedlicher Typen miteinander verglichen werden.
Hinzugefügt in Version 3.11.
IntFlag¶
Die nächste Variante von Enum, die bereitgestellt wird, IntFlag, basiert ebenfalls auf int. Der Unterschied besteht darin, dass IntFlag-Mitglieder mit den bitweisen Operatoren (&, |, ^, ~) kombiniert werden können und das Ergebnis immer noch ein IntFlag-Mitglied ist, wenn möglich. Wie IntEnum sind IntFlag-Mitglieder ebenfalls ganze Zahlen und können überall verwendet werden, wo eine int verwendet wird.
Hinweis
Jede Operation auf einem IntFlag-Mitglied außer den bitweisen Operationen verliert die IntFlag-Mitgliedschaft.
Bitweise Operationen, die zu ungültigen IntFlag-Werten führen, verlieren die IntFlag-Mitgliedschaft. Siehe FlagBoundary für Details.
Hinzugefügt in Version 3.6.
Geändert in Version 3.11.
Beispiel für eine IntFlag-Klasse
>>> from enum import IntFlag
>>> class Perm(IntFlag):
... R = 4
... W = 2
... X = 1
...
>>> Perm.R | Perm.W
<Perm.R|W: 6>
>>> Perm.R + Perm.W
6
>>> RW = Perm.R | Perm.W
>>> Perm.R in RW
True
Es ist auch möglich, die Kombinationen zu benennen.
>>> class Perm(IntFlag):
... R = 4
... W = 2
... X = 1
... RWX = 7
...
>>> Perm.RWX
<Perm.RWX: 7>
>>> ~Perm.RWX
<Perm: 0>
>>> Perm(7)
<Perm.RWX: 7>
Hinweis
Benannte Kombinationen werden als Aliase betrachtet. Aliase werden bei der Iteration nicht angezeigt, können aber bei Lookups nach Wert zurückgegeben werden.
Geändert in Version 3.11.
Ein weiterer wichtiger Unterschied zwischen IntFlag und Enum ist, dass die boolesche Auswertung False ist, wenn keine Flags gesetzt sind (der Wert ist 0).
>>> Perm.R & Perm.X
<Perm: 0>
>>> bool(Perm.R & Perm.X)
False
Da IntFlag-Mitglieder auch Unterklassen von int sind, können sie mit diesen kombiniert werden (können aber die IntFlag-Mitgliedschaft verlieren).
>>> Perm.X | 4
<Perm.R|X: 5>
>>> Perm.X + 8
9
Hinweis
Der Negationsoperator ~ gibt immer ein IntFlag-Mitglied mit einem positiven Wert zurück.
>>> (~Perm.X).value == (Perm.R|Perm.W).value == 6
True
IntFlag-Mitglieder können ebenfalls iteriert werden.
>>> list(RW)
[<Perm.R: 4>, <Perm.W: 2>]
Hinzugefügt in Version 3.11.
Flag¶
Die letzte Variante ist Flag. Wie IntFlag können Flag-Mitglieder mit den bitweisen Operatoren (&, |, ^, ~) kombiniert werden. Im Gegensatz zu IntEnum können sie nicht mit anderen Flag-Enumerationen oder mit int kombiniert oder verglichen werden. Obwohl es möglich ist, die Werte direkt anzugeben, wird empfohlen, auto als Wert zu verwenden und Flag einen geeigneten Wert auswählen zu lassen.
Hinzugefügt in Version 3.6.
Wie bei IntFlag ist die boolesche Auswertung False, wenn eine Kombination von Flag-Mitgliedern dazu führt, dass keine Flags gesetzt sind.
>>> from enum import Flag, auto
>>> class Color(Flag):
... RED = auto()
... BLUE = auto()
... GREEN = auto()
...
>>> Color.RED & Color.GREEN
<Color: 0>
>>> bool(Color.RED & Color.GREEN)
False
Einzelne Flags sollten Werte haben, die Potenzen von zwei sind (1, 2, 4, 8, ...), während Kombinationen von Flags dies nicht tun.
>>> class Color(Flag):
... RED = auto()
... BLUE = auto()
... GREEN = auto()
... WHITE = RED | BLUE | GREEN
...
>>> Color.WHITE
<Color.WHITE: 7>
Das Benennen der Bedingung "keine Flags gesetzt" ändert ihren booleschen Wert nicht.
>>> class Color(Flag):
... BLACK = 0
... RED = auto()
... BLUE = auto()
... GREEN = auto()
...
>>> Color.BLACK
<Color.BLACK: 0>
>>> bool(Color.BLACK)
False
Flag-Mitglieder können ebenfalls iteriert werden.
>>> purple = Color.RED | Color.BLUE
>>> list(purple)
[<Color.RED: 1>, <Color.BLUE: 2>]
Hinzugefügt in Version 3.11.
Hinweis
Für den Großteil neuer Codes werden Enum und Flag dringend empfohlen, da IntEnum und IntFlag einige semantische Versprechen einer Enumeration brechen (indem sie mit ganzen Zahlen vergleichbar sind und somit transitiv mit anderen, nicht zusammenhängenden Enumerationen). IntEnum und IntFlag sollten nur in Fällen verwendet werden, in denen Enum und Flag nicht ausreichen; zum Beispiel, wenn Ganzzahlkonstanten durch Enumerationen ersetzt werden oder für die Interoperabilität mit anderen Systemen.
Andere¶
Obwohl IntEnum Teil des enum-Moduls ist, wäre es sehr einfach, es unabhängig zu implementieren.
class IntEnum(int, ReprEnum): # or Enum instead of ReprEnum
pass
Dies zeigt, wie ähnliche abgeleitete Aufzählungen definiert werden können; zum Beispiel eine FloatEnum, die float anstelle von int einmischt.
Einige Regeln
Beim Unterklassenbildung von
Enummüssen Mix-in-Typen in der Basissequenz vor derEnum-Klasse selbst erscheinen, wie im obigenIntEnum-Beispiel.Mix-in-Typen müssen unterklassifizierbar sein. Zum Beispiel sind
boolundrangenicht unterklassifizierbar und lösen bei der Enum-Erstellung einen Fehler aus, wenn sie als Mix-in-Typ verwendet werden.Obwohl
EnumMitglieder beliebigen Typs haben kann, sobald Sie einen zusätzlichen Typ einmischen, müssen alle Mitglieder Werte dieses Typs haben, z. B.intoben. Diese Einschränkung gilt nicht für Mix-ins, die nur Methoden hinzufügen und keinen anderen Typ angeben.Wenn ein anderer Datentyp eingemischt wird, ist das Attribut
value*nicht dasselbe* wie das Enum-Mitglied selbst, obwohl es äquivalent ist und gleich verglichen wird.Ein
Datentypist ein Mix-in, das__new__()definiert, oder eindataclass%-Formatierung:
%sund%rrufen die__str__()- und__repr__()-Methoden derEnum-Klasse auf; andere Codes (wie%ioder%hfür IntEnum) behandeln das Enum-Mitglied als seinen eingemischten Typ.Formatierte Zeichenkettenliterale (f-strings),
str.format()undformat()verwenden die__str__()-Methode des Enums.
Wann __new__() vs. __init__() verwenden¶
__new__() muss verwendet werden, wenn Sie den tatsächlichen Wert des Enum-Mitglieds anpassen möchten. Alle anderen Modifikationen können entweder in __new__() oder __init__() erfolgen, wobei __init__() bevorzugt wird.
Zum Beispiel, wenn Sie mehrere Elemente an den Konstruktor übergeben möchten, aber nur eines davon der Wert sein soll
>>> class Coordinate(bytes, Enum):
... """
... Coordinate with binary codes that can be indexed by the int code.
... """
... def __new__(cls, value, label, unit):
... obj = bytes.__new__(cls, [value])
... obj._value_ = value
... obj.label = label
... obj.unit = unit
... return obj
... PX = (0, 'P.X', 'km')
... PY = (1, 'P.Y', 'km')
... VX = (2, 'V.X', 'km/s')
... VY = (3, 'V.Y', 'km/s')
...
>>> print(Coordinate['PY'])
Coordinate.PY
>>> print(Coordinate(3))
Coordinate.VY
Warnung
Rufen Sie *nicht* super().__new__() auf, da das nur nachschlagefähige __new__ das ist, das gefunden wird; verwenden Sie stattdessen direkt den Datentyp.
Feinere Punkte¶
Unterstützte __dunder__-Namen¶
__members__ ist eine schreibgeschützte, geordnete Zuordnung von member_name:member-Elementen. Es ist nur auf der Klasse verfügbar.
__new__(), falls angegeben, muss die Enum-Mitglieder erstellen und zurückgeben; es ist auch sehr ratsam, den _value_ des Mitglieds entsprechend zu setzen. Sobald alle Mitglieder erstellt sind, wird es nicht mehr verwendet.
Unterstützte _sunder_-Namen¶
_name_– Name des Mitglieds_value_– Wert des Mitglieds; kann in__new__gesetzt werden_missing_()– eine Nachschlagefunktion, die verwendet wird, wenn ein Wert nicht gefunden wird; kann überschrieben werden_ignore_– eine Liste von Namen, entweder alslistoder alsstr, die nicht in Mitglieder umgewandelt werden und aus der endgültigen Klasse entfernt werden_generate_next_value_()– wird verwendet, um einen geeigneten Wert für ein Enum-Mitglied zu erhalten; kann überschrieben werden_add_alias_()– fügt einen neuen Namen als Alias zu einem bestehenden Mitglied hinzu._add_value_alias_()– fügt einen neuen Wert als Alias zu einem bestehenden Mitglied hinzu. Siehe MultiValueEnum für ein Beispiel.Hinweis
Für Standard-
Enum-Klassen ist der nächste gewählte Wert der höchste gesehene Wert, inkrementiert um eins.Für
Flag-Klassen ist der nächste gewählte Wert die nächste höhere Zweierpotenz.Geändert in Version 3.13: Frühere Versionen verwendeten den letzten gesehenen Wert anstelle des höchsten Werts.
Hinzugefügt in Version 3.6: _missing_, _order_, _generate_next_value_
Hinzugefügt in Version 3.7: _ignore_
Hinzugefügt in Version 3.13: _add_alias_, _add_value_alias_
Um Python 2 / Python 3 Code synchron zu halten, kann ein Attribut _order_ bereitgestellt werden. Es wird mit der tatsächlichen Reihenfolge der Aufzählung verglichen und löst einen Fehler aus, wenn die beiden nicht übereinstimmen.
>>> class Color(Enum):
... _order_ = 'RED GREEN BLUE'
... RED = 1
... BLUE = 3
... GREEN = 2
...
Traceback (most recent call last):
...
TypeError: member order does not match _order_:
['RED', 'BLUE', 'GREEN']
['RED', 'GREEN', 'BLUE']
Hinweis
In Python 2 Code ist das Attribut _order_ notwendig, da die Definitionsreihenfolge verloren geht, bevor sie aufgezeichnet werden kann.
Private Namen¶
Private Namen werden nicht in Enum-Mitglieder umgewandelt, sondern bleiben normale Attribute.
Geändert in Version 3.11.
Enum-Mitgliedstyp¶
Enum-Mitglieder sind Instanzen ihrer Enum-Klasse und werden normalerweise als EnumClass.member zugegriffen. In bestimmten Situationen, wie z. B. beim Schreiben von benutzerdefiniertem Enum-Verhalten, ist der direkte Zugriff auf ein Mitglied von einem anderen nützlich und wird unterstützt; um Namenskonflikte zwischen Mitgliedsnamen und Attributen/Methoden von eingemischten Klassen zu vermeiden, werden Großbuchstaben jedoch dringend empfohlen.
Geändert in Version 3.5.
Erstellen von Mitgliedern, die mit anderen Datentypen gemischt sind¶
Beim Unterklassenbildung anderer Datentypen, wie int oder str, mit einem Enum werden alle Werte nach dem = an den Konstruktor dieses Datentyps übergeben. Zum Beispiel
>>> class MyEnum(IntEnum): # help(int) -> int(x, base=10) -> integer
... example = '11', 16 # so x='11' and base=16
...
>>> MyEnum.example.value # and hex(11) is...
17
Boolescher Wert von Enum-Klassen und -Mitgliedern¶
Enum-Klassen, die mit Nicht-Enum-Typen (wie int, str usw.) gemischt sind, werden gemäß den Regeln des eingemischten Typs ausgewertet; andernfalls werden alle Mitglieder als True ausgewertet. Um die boolesche Auswertung Ihrer eigenen Enum vom Wert des Mitglieds abhängig zu machen, fügen Sie Ihrer Klasse Folgendes hinzu:
def __bool__(self):
return bool(self.value)
Enum-Klassen mit Methoden¶
Wenn Sie Ihrer Enum-Unterklasse zusätzliche Methoden geben, wie die Planet-Klasse unten, erscheinen diese Methoden in einem dir() des Mitglieds, aber nicht der Klasse.
>>> dir(Planet)
['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__members__', '__module__']
>>> dir(Planet.EARTH)
['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', 'surface_gravity', 'value']
Kombinieren von Mitgliedern von Flag¶
Beim Iterieren über eine Kombination von Flag-Mitgliedern werden nur die Mitglieder zurückgegeben, die aus einem einzigen Bit bestehen.
>>> class Color(Flag):
... RED = auto()
... GREEN = auto()
... BLUE = auto()
... MAGENTA = RED | BLUE
... YELLOW = RED | GREEN
... CYAN = GREEN | BLUE
...
>>> Color(3) # named combination
<Color.YELLOW: 3>
>>> Color(7) # not named combination
<Color.RED|GREEN|BLUE: 7>
Flag und IntFlag Details¶
Verwendung des folgenden Snippets für unsere Beispiele
>>> class Color(IntFlag):
... BLACK = 0
... RED = 1
... GREEN = 2
... BLUE = 4
... PURPLE = RED | BLUE
... WHITE = RED | GREEN | BLUE
...
gelten folgende Aussagen
Ein-Bit-Flags sind kanonisch
Mehr-Bit- und Null-Bit-Flags sind Aliase
Nur kanonische Flags werden bei der Iteration zurückgegeben
>>> list(Color.WHITE) [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
Das Negieren eines Flags oder einer Flag-Menge gibt eine neue Flag/Flag-Menge mit dem entsprechenden positiven ganzzahligen Wert zurück
>>> Color.BLUE <Color.BLUE: 4> >>> ~Color.BLUE <Color.RED|GREEN: 3>
Namen von Pseudo-Flags werden aus den Namen ihrer Mitglieder konstruiert
>>> (Color.RED | Color.GREEN).name 'RED|GREEN' >>> class Perm(IntFlag): ... R = 4 ... W = 2 ... X = 1 ... >>> (Perm.R & Perm.W).name is None # effectively Perm(0) True
Mehr-Bit-Flags, auch Aliase genannt, können aus Operationen zurückgegeben werden
>>> Color.RED | Color.BLUE <Color.PURPLE: 5> >>> Color(7) # or Color(-1) <Color.WHITE: 7> >>> Color(0) <Color.BLACK: 0>
Mitgliedschaft / Containment-Prüfung: Nullwertige Flags werden immer als enthalten betrachtet
>>> Color.BLACK in Color.WHITE True
Andernfalls wird nur dann True zurückgegeben, wenn alle Bits eines Flags im anderen Flag enthalten sind.
>>> Color.PURPLE in Color.WHITE True >>> Color.GREEN in Color.PURPLE False
Es gibt einen neuen Grenzwertmechanismus, der steuert, wie Out-of-Range-/ungültige Bits behandelt werden: STRICT, CONFORM, EJECT und KEEP
STRICT -> löst eine Ausnahme aus, wenn ungültige Werte vorhanden sind
CONFORM -> verwirft alle ungültigen Bits
EJECT -> verlieren den Flag-Status und werden zu einem normalen int mit dem gegebenen Wert
KEEP -> behalte die zusätzlichen Bits
behält den Flag-Status und zusätzliche Bits
Zusätzliche Bits erscheinen nicht in der Iteration
Zusätzliche Bits erscheinen in repr() und str()
Der Standard für Flag ist STRICT, der Standard für IntFlag ist EJECT, und der Standard für _convert_ ist KEEP (siehe ssl.Options für ein Beispiel, wann KEEP benötigt wird).
Wie unterscheiden sich Enums und Flags?¶
Enums haben eine benutzerdefinierte Metaklasse, die viele Aspekte sowohl abgeleiteter Enum-Klassen als auch ihrer Instanzen (Mitglieder) beeinflusst.
Enum-Klassen¶
Die Metaklasse EnumType ist verantwortlich für die Bereitstellung von __contains__(), __dir__(), __iter__() und anderen Methoden, die es erlauben, Dinge mit einer Enum-Klasse zu tun, die bei einer typischen Klasse fehlschlagen, wie z. B. list(Color) oder some_enum_var in Color. EnumType ist dafür verantwortlich, sicherzustellen, dass verschiedene andere Methoden der endgültigen Enum-Klasse korrekt sind (wie z. B. __new__(), __getnewargs__(), __str__() und __repr__()).
Flag-Klassen¶
Flags haben eine erweiterte Sicht auf Aliasing: Um kanonisch zu sein, muss der Wert eines Flags eine Zweierpotenz sein und kein Duplikatname. Zusätzlich zur Enum-Definition von Alias gilt ein Flag ohne Wert (auch 0 genannt) oder mit mehr als einer Zweierpotenz (z. B. 3) als Alias.
Enum-Mitglieder (auch Instanzen genannt)¶
Das Interessanteste an Enum-Mitgliedern ist, dass sie Singletons sind. EnumType erstellt sie alle während der Erstellung der Enum-Klasse selbst und setzt dann ein benutzerdefiniertes __new__() ein, um sicherzustellen, dass nie neue instanziiert werden, indem nur die vorhandenen Mitgliedsinstanzen zurückgegeben werden.
Flag-Mitglieder¶
Flag-Mitglieder können wie die Flag-Klasse iteriert werden, und nur die kanonischen Mitglieder werden zurückgegeben. Zum Beispiel
>>> list(Color)
[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
(Beachten Sie, dass BLACK, PURPLE und WHITE nicht angezeigt werden.)
Das Invertieren eines Flag-Mitglieds gibt den entsprechenden positiven Wert zurück, anstatt eines negativen Wertes - zum Beispiel
>>> ~Color.RED
<Color.GREEN|BLUE: 6>
Flag-Mitglieder haben eine Länge, die der Anzahl der von ihnen enthaltenen Zweierpotenzwerte entspricht. Zum Beispiel
>>> len(Color.PURPLE)
2
Enum-Kochbuch¶
Während Enum, IntEnum, StrEnum, Flag und IntFlag die Mehrheit der Anwendungsfälle abdecken sollten, können sie nicht alle abdecken. Hier sind Rezepte für einige verschiedene Arten von Aufzählungen, die direkt oder als Beispiele für die Erstellung eigener verwendet werden können.
Werte weglassen¶
In vielen Anwendungsfällen ist es egal, was der tatsächliche Wert einer Aufzählung ist. Es gibt mehrere Möglichkeiten, diesen einfachen Aufzählungstyp zu definieren
Verwendung von Instanzen von
autofür den WertVerwendung von Instanzen von
objectals WertVerwendung einer beschreibenden Zeichenkette als Wert
Verwendung eines Tupels als Wert und eines benutzerdefinierten
__new__(), um das Tupel durch einenint-Wert zu ersetzen.
Die Verwendung einer dieser Methoden signalisiert dem Benutzer, dass diese Werte nicht wichtig sind, und ermöglicht es auch, Mitglieder hinzuzufügen, zu entfernen oder neu zu ordnen, ohne die verbleibenden Mitglieder neu nummerieren zu müssen.
Verwendung von auto¶
Die Verwendung von auto würde so aussehen
>>> class Color(Enum):
... RED = auto()
... BLUE = auto()
... GREEN = auto()
...
>>> Color.GREEN
<Color.GREEN: 3>
Verwendung von object¶
Die Verwendung von object würde so aussehen
>>> class Color(Enum):
... RED = object()
... GREEN = object()
... BLUE = object()
...
>>> Color.GREEN
<Color.GREEN: <object object at 0x...>>
Dies ist auch ein gutes Beispiel dafür, warum Sie Ihr eigenes __repr__() schreiben möchten.
>>> class Color(Enum):
... RED = object()
... GREEN = object()
... BLUE = object()
... def __repr__(self):
... return "<%s.%s>" % (self.__class__.__name__, self._name_)
...
>>> Color.GREEN
<Color.GREEN>
Verwendung einer beschreibenden Zeichenkette¶
Die Verwendung einer Zeichenkette als Wert würde so aussehen
>>> class Color(Enum):
... RED = 'stop'
... GREEN = 'go'
... BLUE = 'too fast!'
...
>>> Color.GREEN
<Color.GREEN: 'go'>
Verwendung eines benutzerdefinierten __new__()¶
Die Verwendung eines automatisch nummerierenden __new__() würde so aussehen
>>> class AutoNumber(Enum):
... def __new__(cls):
... value = len(cls.__members__) + 1
... obj = object.__new__(cls)
... obj._value_ = value
... return obj
...
>>> class Color(AutoNumber):
... RED = ()
... GREEN = ()
... BLUE = ()
...
>>> Color.GREEN
<Color.GREEN: 2>
Um ein allgemeineres AutoNumber zu erstellen, fügen Sie *args zur Signatur hinzu
>>> class AutoNumber(Enum):
... def __new__(cls, *args): # this is the only change from above
... value = len(cls.__members__) + 1
... obj = object.__new__(cls)
... obj._value_ = value
... return obj
...
Wenn Sie dann von AutoNumber erben, können Sie Ihre eigene __init__ schreiben, um zusätzliche Argumente zu verarbeiten.
>>> class Swatch(AutoNumber):
... def __init__(self, pantone='unknown'):
... self.pantone = pantone
... AUBURN = '3497'
... SEA_GREEN = '1246'
... BLEACHED_CORAL = () # New color, no Pantone code yet!
...
>>> Swatch.SEA_GREEN
<Swatch.SEA_GREEN: 2>
>>> Swatch.SEA_GREEN.pantone
'1246'
>>> Swatch.BLEACHED_CORAL.pantone
'unknown'
Hinweis
Die Methode __new__(), falls definiert, wird während der Erstellung der Enum-Mitglieder verwendet; sie wird dann durch das __new__() von Enum ersetzt, das nach der Klassenerstellung für die Suche nach vorhandenen Mitgliedern verwendet wird.
Warnung
Rufen Sie *nicht* super().__new__() auf, da das nur nachschlagefähige __new__ das ist, das gefunden wird; verwenden Sie stattdessen direkt den Datentyp - z. B.
obj = int.__new__(cls, value)
OrderedEnum¶
Eine geordnete Aufzählung, die nicht auf IntEnum basiert und daher die normalen Enum-Invarianten beibehält (z. B. nicht mit anderen Aufzählungen vergleichbar ist).
>>> class OrderedEnum(Enum):
... def __ge__(self, other):
... if self.__class__ is other.__class__:
... return self.value >= other.value
... return NotImplemented
... def __gt__(self, other):
... if self.__class__ is other.__class__:
... return self.value > other.value
... return NotImplemented
... def __le__(self, other):
... if self.__class__ is other.__class__:
... return self.value <= other.value
... return NotImplemented
... def __lt__(self, other):
... if self.__class__ is other.__class__:
... return self.value < other.value
... return NotImplemented
...
>>> class Grade(OrderedEnum):
... A = 5
... B = 4
... C = 3
... D = 2
... F = 1
...
>>> Grade.C < Grade.A
True
DuplicateFreeEnum¶
Löst einen Fehler aus, wenn ein duplizierter Mitgliedswert gefunden wird, anstatt einen Alias zu erstellen.
>>> class DuplicateFreeEnum(Enum):
... def __init__(self, *args):
... cls = self.__class__
... if any(self.value == e.value for e in cls):
... a = self.name
... e = cls(self.value).name
... raise ValueError(
... "aliases not allowed in DuplicateFreeEnum: %r --> %r"
... % (a, e))
...
>>> class Color(DuplicateFreeEnum):
... RED = 1
... GREEN = 2
... BLUE = 3
... GRENE = 2
...
Traceback (most recent call last):
...
ValueError: aliases not allowed in DuplicateFreeEnum: 'GRENE' --> 'GREEN'
Hinweis
Dies ist ein nützliches Beispiel für die Unterklassenbildung von Enum, um andere Verhaltensweisen hinzuzufügen oder zu ändern sowie Aliase zu verbieten. Wenn nur das Verbot von Aliassen gewünscht ist, kann stattdessen der Dekorator unique() verwendet werden.
MultiValueEnum¶
Unterstützt mehr als einen Wert pro Mitglied.
>>> class MultiValueEnum(Enum):
... def __new__(cls, value, *values):
... self = object.__new__(cls)
... self._value_ = value
... for v in values:
... self._add_value_alias_(v)
... return self
...
>>> class DType(MultiValueEnum):
... float32 = 'f', 8
... double64 = 'd', 9
...
>>> DType('f')
<DType.float32: 'f'>
>>> DType(9)
<DType.double64: 'd'>
Planet¶
Wenn __new__() oder __init__() definiert ist, wird der Wert des Enum-Mitglieds an diese Methoden übergeben.
>>> class Planet(Enum):
... MERCURY = (3.303e+23, 2.4397e6)
... VENUS = (4.869e+24, 6.0518e6)
... EARTH = (5.976e+24, 6.37814e6)
... MARS = (6.421e+23, 3.3972e6)
... JUPITER = (1.9e+27, 7.1492e7)
... SATURN = (5.688e+26, 6.0268e7)
... URANUS = (8.686e+25, 2.5559e7)
... NEPTUNE = (1.024e+26, 2.4746e7)
... def __init__(self, mass, radius):
... self.mass = mass # in kilograms
... self.radius = radius # in meters
... @property
... def surface_gravity(self):
... # universal gravitational constant (m3 kg-1 s-2)
... G = 6.67300E-11
... return G * self.mass / (self.radius * self.radius)
...
>>> Planet.EARTH.value
(5.976e+24, 6378140.0)
>>> Planet.EARTH.surface_gravity
9.802652743337129
TimePeriod¶
Ein Beispiel zur Veranschaulichung der Verwendung des Attributs _ignore_.
>>> from datetime import timedelta
>>> class Period(timedelta, Enum):
... "different lengths of time"
... _ignore_ = 'Period i'
... Period = vars()
... for i in range(367):
... Period['day_%d' % i] = i
...
>>> list(Period)[:2]
[<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]
>>> list(Period)[-2:]
[<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]
Unterklassenbildung von EnumType¶
Während die meisten Enum-Anforderungen durch die Anpassung von Enum-Unterklassen erfüllt werden können, entweder mit Klassen-Dekoratoren oder benutzerdefinierten Funktionen, kann EnumType unterklassifiziert werden, um eine andere Enum-Erfahrung zu bieten.