Die Deklaration von Pythons enum.Enum
erfordert, dass Werte bereitgestellt werden, wenn sie im einfachsten Fall verwendet werden Für ein Enum interessieren uns Namen und Werte nicht. Wir kümmern uns nur um die Wächter. Nachdem ich kürzlich Q & A gelesen habe, habe ich festgestellt, dass es möglich ist, __prepare__
Methode der Enum-Metaklasse, um diese Art von Deklaration zu erhalten:
Und die Umsetzung, um die Dinge so trocken zu machen, ist eigentlich ziemlich einfach:
%Vor% In Python 3.6 wurde enum.auto
zur Verfügung gestellt, um bei diesem Problem zu helfen von Werte weglassen , aber die Benutzeroberfläche ist immer noch seltsam - Sie müssen angeben auto()
-Wert für jedes Mitglied und erben von einer anderen Basis, die __repr__
festlegt:
In Anbetracht der Tatsache, dass viele Arbeitsstunden und große Sorgfalt in die für die Standardbibliothek gewählte Implementierung eingeflossen sind, muss es einen Grund geben, warum die wohl früher gezeigte Python-Version einer deklarativen Enumeration nicht richtig funktioniert.
Meine Frage ist, was sind die Probleme und Fehlerarten des vorgeschlagenen Ansatzes, und warum wurde dies (oder etwas Ähnliches) dagegen entschieden - mit dem Feature auto
, das stattdessen in Python 3.6 enthalten ist?
Es gibt mehrere Fehler, wenn ein defaultdict
der Namensraum der Enum ist:
_EnumDict
namespace:
_generate
Und das Wichtigste:
Warum wird es nicht funktionieren? % Co_de% kann nicht nur Attribute für den Namespace dict setzen, sondern auch den Namespace dict selbst - und __prepare__
: _EnumDict
, eine Liste aller Attribute, die Mitglieder sein sollten.
Allerdings ist das Ziel, einen Namen ohne Wert zu deklarieren, nicht unmöglich - die _member_names
1 Paket erlaubt es mit ein paar Sicherheitsvorkehrungen:
aenum
, property
und classmethod
sind standardmäßig ausgeschlossen, aber man kann sie einschließen und / oder andere globale Namen ausschließen Dieses Verhalten wurde jedoch für die stdlib als zu magisch angesehen. Wenn Sie es also wollen, zusammen mit einigen anderen Verbesserungen / Verbesserungen 2 , müssen Sie staticmethod
verwenden.
Ein Beispiel:
%Vor% Die aenum
zeigt jedoch immer noch die erstellten Werte.
-
1 Offenlegung: Ich bin der Autor der Python stdlib __repr__
, der Enum
Rückport und der Erweiterte Aufzählung ( enum34
) Bibliothek.
2 aenum
(genau wie es sagt;), NamedConstant
(auf Metaklassen basierend, Standardwerte usw.), plus einige eingebaute Enums:
NamedTuple
- & gt; Mehrere Werte können einem Namen zugeordnet werden (keine Aliase) MultiValueEnum
- & gt; Namen mit dem gleichen Wert sind keine Aliase (denken Sie an Karten) NoAliasEnum
- & gt; Mitglieder sind per Definition OrderedEnum
- & gt; keine Aliase erlaubt Es könnte Sie interessieren, dass Sie Enums mithilfe mehrerer Argumente erstellen können:
%Vor% Auf diese Weise müssen Sie auto
oder irgendetwas anderes (wie __prepare__
) nicht verwenden.
Warum hat sich das (oder etwas Ähnliches) dagegen entschieden - mit der Auto-Funktion, die stattdessen in Python 3.6 enthalten ist?
Dies wurde ausführlich im Python-Issue-Tracker (insbesondere bpo-23591 ) besprochen und ich werde den (zusammenfassend ) Argumente dagegen:
Dies ist etwas Grundsätzliches: Es bricht das Versprechen, dass der Klassenkörper eine Reihe von Befehlen ist, wobei Python-Anweisungen (wie die Zuweisung) ihre übliche Semantik haben.
Solange [auto] irgendwo definiert wurde (d. h. von enum import [auto]), ist es normales Python und kämpft nicht mit dem Rest der Sprache oder seinen Toolchains.
Kurz gesagt: Klassendefinitionen interpretieren diese "Variablen" als Suchvorgänge:
%Vor% aber für enum
sollten sie als Zuweisungen interpretiert werden? Dieser Anwendungsfall wurde nicht als "speziell genug angesehen, um die Regeln zu brechen" .
Wenn Sie das tun, können Sie nicht auf globale oder integrierte Variablen innerhalb des Klassenkörpers zugreifen, da jeder Versuch vom defaultdict abgefangen wird. Dazu gehören Dinge wie Dekorateure:
%Vor%Die Ergebnisse sind seltsam, verwirrend und wahrscheinlich nicht wert.
Tags und Links python enums metaclass python-3.6