Das Modul enum wurde aus Python 3.4 hinzugefügt. Ein Paket, das für Versionen unter 3.4 (einschließlich 2.x) zurückportiert wurde, ist bei PyPI als [enum34] registriert (https://pypi.python.org/pypi/enum34).
Wenn Sie das Enum-Modul noch nie verwendet haben, ist der folgende Artikel hilfreich.
Eine Notiz von Nick Coghlan, dem Hauptentwickler von CPython, bietet Hintergrundinformationen zur Standardbibliothek von enum und eine Zusammenfassung der damaligen Diskussionen.
Pythons Aufzählung kann mit * Good Enough * zufriedenstellend sein, da sie ursprünglich nicht Standard war.
Was fehlt im Gegenteil? Es gibt ein Buch mit dem Titel Effective Java, das wie eine Bibel in der Java-Welt aussieht und ein Kapitel über die Best Practices von enum abdeckt. Ich werde.
In der Java-Welt wird enum häufig verwendet, da es eine Vielzahl von Anwendungen bietet und eine praktische Funktion darstellt, z. B. die Gewährleistung der Typensicherheit beim Kompilieren und die Implementierung eines Singletons. Während ich mir Effective Java ansah, versuchte ich, die Funktionen zu erweitern, die Python enum nicht hat.
extenum
Ich habe ein [extenum] -Paket (https://pypi.python.org/pypi/extenum) erstellt, das das Standard-Enum-Modul erweitert.
$ pip install extenum
Gemäß offizielle Dokumententerminologie
>> from enum import Enum >> class Color(Enum):
... red = 1 ... green = 2 ... blue = 3 ...
> Kommentarbedingungen
> * Die Klasse `Color` ist ein Aufzählungstyp (oder Enum).
> * Die Attribute `Color.red`,` Color.green` und andere sind Mitglieder des Aufzählungstyps (oder Enum-Mitglieder).
> * Mitglieder des Aufzählungstyps haben einen Namen und einen Wert (`Color.red` hat den Namen` red`,` Color.blue` hat den Wert 3 usw.).
Die durch den Aufzählungstyp definierten Konstanten sind als *** Aufzählungstypelemente (oder Aufzählungselemente) *** definiert. In anderen Sprachen wird es auch als Enumerator oder Enumerationskonstante bezeichnet. Ich denke, dass Aufzählungskonstanten leichter zu verstehen sind, weil ich erwarte, dass sie eine Rolle als Konstanten spielen, aber in Übereinstimmung mit der offiziellen Dokumentation werde ich in diesem Dokument Aufzählungstypkonstanten als Aufzählungstypelemente bezeichnen.
### Ständige Implementierung fester Methoden
Effektives Java wird als Konstante bezeichnet, aber diese * Konstante * bezieht sich auf ein Mitglied des Aufzählungstyps.
Der Grund, warum ich mich für Extenum entschieden habe, war, dass dieser Mechanismus nicht verfügbar war. Als ich nach festen Konstantenmethoden suchte, fand ich [asym-enum](https://github.com/AsymmetricVentures/asym-enum#methods-and-functions) als so etwas.
#### **`3.4`**
```python
from asymm_enum.enum import Enum
class E(Enum):
A = 1
B = 2
def get_label(self):
''' instance methods are attached to individual members '''
return self.label
@classmethod
def get_b_label(cls):
''' class methods are attached to the enum '''
return cls.B.label
Ich fand das etwas hässlich und beschloss, es selbst zu machen.
Mit extenum können Sie es folgendermaßen implementieren:
constant_specific_enum.py
from extenum import ConstantSpecificEnum
class Operation(ConstantSpecificEnum):
PLUS = '+'
MINUS = '-'
TIMES = '*'
DIVIDE = '/'
@overload(PLUS)
def apply(self, x, y):
return x + y
@overload(MINUS)
def apply(self, x, y):
return x - y
@overload(TIMES)
def apply(self, x, y):
return x * y
@overload(DIVIDE)
def apply(self, x, y):
return x / y
Ich konnte es ordentlich umsetzen.
Da Python keinen Überladungsmechanismus hat, implementiert * @ overload (CONSTANT)
* eine feste Konstantenmethode mit einem Dekorator.
3.4
>>> from constant_specific_enum import Operation
>>> for name, const in Operation.__members__.items():
... print(name, ':', const.apply(2, 4))
PLUS : 6
MINUS : -2
TIMES : 8
DIVIDE : 0.5
Feste konstante Methoden sind auch nützlich, um Absichten über den Namen der Methode zu kommunizieren. Schauen wir uns zum Beispiel einen Aufzählungstyp an, der Informationen zum Verarbeitungsstatus enthält.
3.4
from extenum import ConstantSpecificEnum
class Status(ConstantSpecificEnum):
PREPARING = 1
WAITING = 2
RUNNING = 3
@overload(PREPARING)
def is_cancelable(self):
return False
@overload(WAITING)
def is_cancelable(self):
return True
@overload(RUNNING)
def is_cancelable(self):
return True
Angenommen, jedes Aufzählungsmitglied zeigt auf einen Statuswert, aber Sie müssen feststellen, ob es sich um einen abbrechbaren Status handelt, bevor Sie diesen Vorgang abbrechen können.
Wenn es keine feste Konstantenmethode gibt, prüfen wir, ob das an eine Funktion übergebene Element des Aufzählungstyps entweder * WAITING * oder * RUNNING * ist.
3.4
def cancel(status):
if status in [Status.WAITING, Status.RUNNING]:
# do cancel
Dies erfordert, dass der Implementierer oder Leser der Abbruchfunktion die Details des Aufzählungstyps für Statusinformationen kennt und möglicherweise die Bedingungen in dieser Funktion ändern muss, wenn die Statusinformationen zunehmen.
Wenn Sie eine Methode mit fester Konstante haben, kann die Statusbeurteilung der Vorverarbeitung dieser Abbruchfunktion natürlicher und übersichtlicher geschrieben werden.
3.4
def cancel(status):
if status.is_cancelable():
# do cancel
Im Vergleich zum obigen Code ist es für Implementierer und Leser der Abbruchfunktion einfacher zu verstehen, und selbst wenn die Statusinformationen zunehmen, muss nur eine aufgezählte feste Konstantenmethode hinzugefügt werden.
Dies ist ein Anwendungsbeispiel für die Implementierung einer konstanten festen Methode. Es ist für eine konservativere Implementierung vorgesehen, indem Aufzählungstypen von Tages- und Wochentags- / Feiertagsattributen verschachtelt werden.
strategy_enum_pattern.py
from extenum import ConstantSpecificEnum
class PayrollDay(ConstantSpecificEnum):
class PayType(ConstantSpecificEnum):
WEEKDAY = 1
WEEKEND = 2
@overload(WEEKDAY)
def overtime_pay(self, hours, pay_rate):
return 0 if hours <= 8 else (hours - 8) * pay_rate / 2
@overload(WEEKEND)
def overtime_pay(self, hours, pay_rate):
return hours * pay_rate / 2
def pay(self, hours_worked, pay_rate):
base_pay = hours_worked * pay_rate
overtime_pay = self.overtime_pay(hours_worked, pay_rate)
return base_pay + overtime_pay
MONDAY = PayType.WEEKDAY
TUESDAY = PayType.WEEKDAY
WEDNESDAY = PayType.WEEKDAY
THURSDAY = PayType.WEEKDAY
FRIDAY = PayType.WEEKDAY
SATURDAY = PayType.WEEKEND
SUNDAY = PayType.WEEKEND
def pay(self, hours_worked, pay_rate):
return self.value.pay(hours_worked, pay_rate)
Java ist als Übung nützlich, aber Python fühlt sich übertrieben (subjektiv). Ich habe versucht, es umzusetzen, aber ich denke, dass es ein subtiles Beispiel ist, von dem nicht gesagt werden kann, dass es gut oder schlecht ist.
Bitte sehen Sie, inwieweit Sie so etwas tun können.
3.4
>>> from strategy_enum_pattern import PayrollDay
>>> PayrollDay.MONDAY.pay(10, 1000.0)
11000.0
>>> PayrollDay.WEDNESDAY.pay(8, 1000.0)
8000.0
>>> PayrollDay.SATURDAY.pay(10, 1000.0)
15000.0
>>> PayrollDay.SUNDAY.pay(8, 1000.0)
12000.0
Da die Mitglieder des Aufzählungstyps Klassenvariablen definieren, kann der folgende Aufzählungstyp nicht definiert werden.
3.4
class Color(Enum):
red, green, blue
Wenn ich es ausführe, erhalte ich * NameError *.
3.4
NameError: name 'red' is not defined
Aufzählungsmodul hinzugefügt [PEP 435 - Keine Werte für Aufzählungen angeben müssen-](https://www.python.org/dev/peps/pep-0435/#not-having-to-specify-values-for- nach Aufzählungen)
Cons: involves much magic in the implementation, which makes even the definition of such enums baffling when first seen. Besides, explicit is better than implicit.
Gründe, warum es nicht möglich ist, einen impliziten Wert zu definieren, sind, dass die Implementierung magisch, auf den ersten Blick verwirrend und eher dem expliziten Zen als dem impliziten widerspricht.
Dies ist für die Python-Kultur korrekt, daher ist es in Ordnung, aber Nick Coghlans Hinweis Unterstützung für alternative Deklarationssyntaxen enum_creation.html (Unterstützung für alternative Deklarationssyntaxen) erwähnt, wie implizite Aufzählungsmitglieder implementiert werden.
Implicit enums that don’t really support normal code execution in the class body, and allow the above to be simplified further. It’s another variant of the autonumbered example in the test suite, but one that diverges substantially from normal Python semantics: merely mentioning a name will create a new reference to that name. While there are a number of ways to get into trouble when doing this, the basic concept would be to modify
__prepare__
on the metaclass to return a namespace that implements__missing__
as returning a custom sentinel value and overrides__getitem__
to treat repeating a name as an error:
Python ~~ Black Magic ~~ Es ist eine interessante Methode für die Metaprogrammierung, also habe ich sie implementiert.
Die spezielle Methode __prepare__
wurde aus Python 3 hinzugefügt und die Metaklasse wird initialisiert. Hängt den Prozess der Rückgabe des Namespace dieser Klasse an, wenn __missing__
verknüpft die KeyError-Fehlerbehandlung für Wörterbuchunterklassen, wenn der Schlüssel nicht im Wörterbuch vorhanden ist Machen.
Sie können die Definition des Namespace einer Klasse verknüpfen, indem Sie ein Wörterbuch mit "missing" als Namespace-Objekt im vorherigen "prepare" zurückgeben.
Ich weiß nicht, wovon du sprichst, also lass es uns codieren.
prepare_missing.py
class MyNameSpace(dict):
def __missing__(self, key):
self[key] = value = 'x'
return value
class MyMetaclass(type):
@classmethod
def __prepare__(metacls, cls, bases):
return MyNameSpace()
def __new__(metacls, cls, bases, classdict):
print('classdict is', classdict.__class__)
return super().__new__(metacls, cls, bases, classdict)
Verwenden Sie diese Metaklasse, um eine Klasse zu definieren.
3.4
>>> from prepare_missing import MyMetaclass
>>> class Color(metaclass=MyMetaclass):
... red, green, blue
...
classdict is <class 'status.MyNameSpace'>
>>> Color.red
'x'
>>> Color.blue
'x'
Beim Definieren einer Klasse wird die Methode newder Metaklasse * MyMetaclass * aufgerufen und * MyNameSpace * an den Klassennamensraum (* classdict *) übergeben. Der * MyNameSpace *
missing` legt die Zeichenfolge * x * für Namen fest, die keinen Schlüssel haben, dh nicht im Klassennamensraum vorhanden sind.
3.4
>>> from extenum import ImplicitEnum
>>> class Color(ImplicitEnum):
... RED
... GREEN
... BLUE
...
>>> for name, const in Color.__members__.items():
... print(name, ':', const.value)
...
RED : 1
GREEN : 2
BLUE : 3
Abgesehen davon wird der * @ overload
* -Dekorator von * ConstantSpecificEnum * im vorherigen Abschnitt ebenfalls mit diesem Mechanismus implementiert. Ich denke, es gibt Vor- und Nachteile, diese Dekoratordefinition selbst zu verbergen, aber selbst wenn sie verborgen ist, fühlt sie sich von der Benutzerseite seltsam an, so dass * @ classmethod
* und * @ staticmethod
* global behandelt werden können. Ich fragte mich, ob es einen gab.
EnumSet EnumSet ist wie eine Utility-Klasse, die eine Menge mit Enum-Konstanten erstellt. Ich habe es implementiert, als ich mir Java's [EnumSet] angesehen habe (http://docs.oracle.com/javase/jp/8/docs/api/java/util/EnumSet.html).
Für leicht verständliche Zwecke schafft die Verwendung von EnumSet zur Implementierung von Verarbeitungen wie Flag-Operationen, die durch Bitarithmetik implementiert wurden, eine Atmosphäre, die für Menschen einfach ist.
3.4
>>> from enum import Enum
>>> class Mode(Enum):
... READ = 4
... WRITE = 2
... EXECUTE = 1
...
Versuchen wir, diesen Aufzählungstyp * Mode * zu verwenden.
3.4
>>> from extenum import EnumSet
>>> EnumSet.all_of(Mode) #Generieren Sie ein EnumSet, das alle aufgezählten Mitglieder des Modus enthält
EnumSet({<Mode.READ: 4>, <Mode.WRITE: 2>, <Mode.EXECUTE: 1>})
>>> EnumSet.none_of(Mode) #Generieren Sie ein leeres EnumSet, das ein aufgezähltes Mitglied von Mode akzeptiert
EnumSet()
>>> enumset = EnumSet.of(Mode.READ, Mode.EXECUTE) #Generieren Sie ein EnumSet, das ein beliebiges Aufzählungsmitglied enthält
>>> enumset
EnumSet({<Mode.READ: 4>, <Mode.EXECUTE: 1>})
>>> enumset.update(EnumSet.of(Mode.READ, Mode.WRITE))
>>> enumset
EnumSet({<Mode.READ: 4>, <Mode.WRITE: 2>, <Mode.EXECUTE: 1>})
>>> Mode.WRITE in enumset
True
>>> 2 in enumset
False
Das Zusammenstellen in einem EnumSet erleichtert die Handhabung von Modi und Optionen.
Die folgenden Funktionen werden von extenum als Java-ähnliche Enum-Erweiterung bereitgestellt.
Es erbt und erweitert die Standards * Enum *, * EnumMeta * und * _EnumDict *, sodass es wahrscheinlich problemlos als regulärer Aufzählungstyp funktioniert.
Bitte lassen Sie uns wissen, ob es andere Aufzählungspraktiken gibt, die interessant sein könnten. Manchmal ist der Zweck, es zu machen, anstatt es zu benutzen.