__prepare__ für ein Enum verwenden ... was ist der Haken?

8

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:

%Vor%

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:

%Vor%

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?

    
wim 08.05.2017, 18:46
quelle

3 Antworten

7

Es gibt mehrere Fehler, wenn ein defaultdict der Namensraum der Enum ist:

  • kann nur auf andere enum-Member / Methoden zugreifen
  • Tippfehler erstellen neue Mitglieder
  • Verlustschutz von _EnumDict namespace:
    • überschreiben von Mitgliedern
    • Überschreibungsmethoden
    • die neuere Methode _generate

Und das Wichtigste:

  • es wird nicht funktionieren

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:

  • magisches automatisches Verhalten ist nur beim Definieren von Elementen vorhanden (sobald eine normale Methode definiert ist, wird es deaktiviert)
  • 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
  • vergleichbar
  • OrderedEnum - & gt; keine Aliase erlaubt
Ethan Furman 08.05.2017, 19:12
quelle
1

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:

Vedran Čačić :

  

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.

Raymond Hettinger :

  

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

    
MSeifert 08.05.2017 19:41
quelle
0

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.

    
user2357112 08.05.2017 18:53
quelle

Tags und Links