Python, wofür ist der Enum-Typ gut? [Duplikat]

7

In Python 3.4 haben wir eine Enum lib in der Standardbibliothek erhalten: enum . Wir können einen Backport für enum erhalten, der mit Python 2.4 bis 2.7 (und sogar 3.1 bis 3.3), enum34 funktioniert Pypi.

Aber wir haben es geschafft, lange ohne dieses neue Modul auszukommen - warum haben wir es jetzt?

Ich habe eine allgemeine Idee über den Zweck von enums aus anderen Sprachen. In Python war es üblich, eine nackte Klasse wie folgt zu verwenden und sich dabei auf eine enum zu beziehen:

%Vor%

Dies kann in einer API verwendet werden, um eine kanonische Repräsentation des Wertes zu erstellen, z. B .:

%Vor%

Wenn das irgendwelche Kritikpunkte hat, ist es veränderbar, Sie können es nicht (einfach) iterieren, und wie sollen wir die Semantik der Ganzzahl 2 ?

kennen

Dann könnte ich wohl etwas wie ein namentlich genanntes Tupel verwenden, das unveränderlich wäre?

%Vor%

Die Erstellung des namedtuple ist ein wenig überflüssig (wir müssen jeden Namen zweimal schreiben) und so etwas unelegant. Die "Nummer" der Farbe zu bekommen ist auch ein wenig unelegant (wir müssen colors zweimal schreiben). Die Wertprüfung muss mit Strings durchgeführt werden, was etwas weniger effizient ist.

Also zurück zu enums.

Was ist der Zweck von enums? Welchen Wert schaffen sie für die Sprache? Wann sollte ich sie verwenden und wann sollte ich sie vermeiden?

    
Aaron Hall 02.06.2016, 20:36
quelle

1 Antwort

33
  

Was ist der Zweck von enums? Welchen Wert schaffen sie für die Sprache? Wann sollte ich sie verwenden und wann sollte ich sie vermeiden?

Der Enum-Typ wurde über PEP 435 in Python eingefügt. Die Begründung ist:

  

Die Eigenschaften einer Enumeration sind nützlich, um eine unveränderliche, verwandte Menge von konstanten Werten zu definieren, die eine semantische Bedeutung haben können oder nicht.

Bei Verwendung von Zahlen und Strings für diesen Zweck könnten sie als "magische Zahlen" oder " magische Saiten ". Zahlen tragen selten die Semantik mit sich, und Zeichenfolgen werden leicht verwirrt (Großschreibung? Rechtschreibung? Schlange oder Kamelfall?)

Tage der Woche und Schulbriefnoten sind Beispiele für diese Art von Wertesammlungen.

Hier sehen Sie ein Beispiel aus den Dokumenten :

%Vor%

Wie die nackte Klasse ist dies viel lesbarer und eleganter als das benannte Beispiel, es ist auch unveränderlich und hat weitere Vorteile, wie wir weiter unten sehen werden.

Streng dominant: Der Typ des Enum-Members ist das Enum

%Vor%

Damit können Sie Funktionen für die Mitglieder in der Enum-Definition definieren. Das Definieren der Funktionalität für die Werte könnte mit den anderen früheren Methoden erreicht werden, wäre aber sehr unelegant.

Verbesserung: Stringzwang

Die String-Darstellung ist für den Menschen lesbar, während der Ausdruck mehr Informationen enthält:

%Vor%

Ich finde dies eine Verbesserung gegenüber den magischen Zahlen und sogar möglicherweise besser als Strings aus dem namedtuple.

Iteration (Parität):

Die Enumeration unterstützt Iteration (wie das namedtuple, aber nicht so sehr die nackte Klasse):

%Vor%

Das Attribut __members__ ist ein OrderedDict , das die Namen der Enums ihren jeweiligen Enum-Objekten zuordnet (ähnlich wie die Funktion _asdict() von nametuple).

Unterstützt von Pickle (Parität)

Sie können die Enumeration serialisieren und deserialisieren (falls jemand sich darüber Gedanken machte):

%Vor%

Verbesserung: Aliase

Dies ist ein nettes Feature, das die nackte Klasse nicht hat, und es wäre schwierig zu sagen, dass der Alias ​​dort in namedtuple vorhanden war.

%Vor%

Der Alias ​​kommt nach dem kanonischen Namen, aber sie sind beide gleich:

%Vor%

Wenn Aliase verboten werden sollten, um Wertkollisionen zu vermeiden, verwenden Sie enum.unique decorator (ein streng dominantes Merkmal).

Streng dominant: Vergleiche mit is

Die Enumeration soll mit is getestet werden, was eine schnelle Überprüfung der Identität eines einzelnen Objekts im Prozess ist.

%Vor%

Tests für Gleichheit funktionieren ebenfalls, aber Tests auf Identität mit is sind optimal.

Unterschiedliche Semantik zu anderen Python-Klassen

Enum-Klassen haben eine andere Semantik als reguläre Python-Typen. Die Werte der Enum sind Instanzen der Enum und sind Singletons im Speicher für diese Werte - es gibt keinen anderen Zweck, sie zu instanziieren.

%Vor%

Dies ist wichtig zu beachten, vielleicht ist es ein Nachteil, aber Vergleichen in dieser Dimension vergleicht Äpfel mit Orangen.

Enums wird nicht als geordnet angenommen

Während die Enum-Klasse weiß, in welcher Reihenfolge die Elemente erstellt werden, wird nicht davon ausgegangen, dass Enums geordnet sind. Dies ist ein Merkmal, da viele Dinge, die aufgezählt werden können, keine natürliche Reihenfolge haben, und daher wäre die Reihenfolge beliebig.

Sie können jedoch Ihre Bestellungen aufgeben (siehe nächsten Abschnitt).

Unterklassierung

Sie können keine Enum mit deklarierten Membern ableiten, aber Sie können eine Enum-Klasse ableiten, die keine Member für das gemeinsame Verhalten deklariert (siehe OrderedEnum-Rezept im docs ).

Dies ist ein Feature - es macht wenig Sinn, ein Enum mit Mitgliedern zu untergliedern, aber der Vergleich ist wiederum Äpfel und Orangen.

Wann sollte ich enum.Enum verwenden?

Dies ist die neue kanonische Enumeration in Python. Mitarbeiter erwarten von Ihren Enums, dass sie sich wie diese Enums verhalten.

Verwenden Sie es überall dort, wo Sie eine kanonische Quelle von Aufzählungsdaten in Ihrem Code haben, wo Sie explizit den kanonischen Namen anstelle von beliebigen Daten angeben möchten.

Wenn Sie beispielsweise in Ihrem Code angeben möchten, dass es nicht "Green" , "green" , 2 oder "Greene" , sondern Color.green ist, verwenden Sie das enum.Enum-Objekt. Es ist sowohl explizit als auch spezifisch.

Es gibt viele Beispiele und Rezepte in der Dokumentation .

>

Wann sollte ich sie vermeiden?

Hör auf, deine eigenen zu rollen oder lass die Leute über magische Zahlen und Saiten raten. Weiche ihnen nicht aus. Umfassen Sie sie.

Wenn jedoch Ihre enum-Member aus historischen Gründen Integer sein müssen, gibt es das IntEnum aus demselben Modul, das das gleiche Verhalten hat, aber es ist auch eine ganze Zahl, weil es das eingebaute int vor dem Unterklassen% subklassifiziert Code%. Von Enum s Hilfe:

%Vor%

können wir sehen, dass die IntEnum-Werte als eine Instanz von IntEnum getestet würden.

    
Aaron Hall 02.06.2016, 20:36
quelle

Tags und Links