Ich bin hauptsächlich ein C # -Entwickler, arbeite aber derzeit an einem Projekt in Python.
Wie kann ich das Äquivalent einer Aufzählung in Python darstellen?
quelle
Ich bin hauptsächlich ein C # -Entwickler, arbeite aber derzeit an einem Projekt in Python.
Wie kann ich das Äquivalent einer Aufzählung in Python darstellen?
Python 3.4 wurden Enums hinzugefügt, wie in PEP 435 beschrieben . Es wurde auch auf 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 und 2.4 zurückportiert zurückportiert.
Versuchen Sie für fortgeschrittenere Enum-Techniken die Aenum-Bibliothek (2.7, 3.3+, derselbe Autor wie enum34
. Der Code ist zwischen py2 und py3 nicht perfekt kompatibel, z. B. __order__
in Python 2 ).
enum34
, tun$ pip install enum34
aenum
, tun$ pip install aenum
Durch die Installation enum
(keine Nummern) wird eine völlig andere und inkompatible Version installiert.
from enum import Enum # for enum34, or the stdlib version
# from aenum import Enum # for the aenum version
Animal = Enum('Animal', 'ant bee cat dog')
Animal.ant # returns <Animal.ant: 1>
Animal['ant'] # returns <Animal.ant: 1> (string lookup)
Animal.ant.name # returns 'ant' (inverse lookup)
oder äquivalent:
class Animal(Enum):
ant = 1
bee = 2
cat = 3
dog = 4
In früheren Versionen ist eine Möglichkeit, Aufzählungen zu erstellen, folgende:
def enum(**enums):
return type('Enum', (), enums)
was so verwendet wird:
>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'
Sie können die automatische Aufzählung auch problemlos mit folgenden Funktionen unterstützen:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
return type('Enum', (), enums)
und wie folgt verwendet:
>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1
Die Unterstützung für die Rückkonvertierung der Werte in Namen kann folgendermaßen hinzugefügt werden:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
reverse = dict((value, key) for key, value in enums.iteritems())
enums['reverse_mapping'] = reverse
return type('Enum', (), enums)
Dies überschreibt alles mit diesem Namen, ist jedoch nützlich, um Ihre Aufzählungen in der Ausgabe zu rendern. Es wird KeyError ausgelöst, wenn die umgekehrte Zuordnung nicht vorhanden ist. Mit dem ersten Beispiel:
>>> Numbers.reverse_mapping['three']
'THREE'
**named
) in der Enum-Funktion für ältere Versionen soll benutzerdefinierte Werte unterstützen:enum("blue", "red", "green", black=0)
Vor PEP 435 hatte Python kein Äquivalent, aber Sie konnten Ihr eigenes implementieren.
Ich selbst mag es einfach zu halten (ich habe einige schrecklich komplexe Beispiele im Netz gesehen), so etwas ...
In Python 3.4 ( PEP 435 ) können Sie Enum zur Basisklasse machen. Dadurch erhalten Sie ein wenig zusätzliche Funktionalität, die im PEP beschrieben wird. Beispielsweise unterscheiden sich Enum-Mitglieder von Ganzzahlen und setzen sich aus a
name
und a zusammenvalue
.Wenn Sie die Werte nicht eingeben möchten, verwenden Sie die folgende Verknüpfung:
Enum
Implementierungen können in Listen konvertiert werden und sind iterierbar . Die Reihenfolge ihrer Mitglieder ist die Deklarationsreihenfolge und hat nichts mit ihren Werten zu tun. Zum Beispiel:quelle
object()
.Hier ist eine Implementierung:
Hier ist seine Verwendung:
quelle
__setattr__(self, name, value)
und__delattr__(self, name)
wenn Sie versehentlich schreibenAnimals.DOG = CAT
, ist dies möglicherweise nicht im Hintergrund erfolgreich.Animals.DOG
; Außerdem sind die Werte der Konstanten Zeichenfolgen, sodass Vergleiche mit diesen Konstanten langsamer sind, als wenn beispielsweise Ganzzahlen als Werte zulässig wären.setattr()
Funktion inside__init__()
method zu verwenden, anstatt die Methode zu überschreiben__getattr__()
. Ich gehe davon aus, dass dies genauso funktionieren soll: Klasse Enum (Objekt): def __init __ (self, enum_string_list): if type (enum_string_list) == list: für enum_string in enum_string_list: setattr (self, enum_string, enum_string) else: raise AttributeErrortry-except
Block eine Mitgliedschaft festgelegt ist ?Wenn Sie die numerischen Werte benötigen, ist dies der schnellste Weg:
In Python 3.x können Sie am Ende auch einen markierten Platzhalter hinzufügen, der alle verbleibenden Werte des Bereichs aufnimmt, falls Sie nichts dagegen haben, Speicher zu verschwenden, und nicht zählen können:
quelle
Die beste Lösung für Sie hängt davon ab, was Sie von Ihrer Fälschung benötigen
enum
.Einfache Aufzählung:
Wenn Sie
enum
nur eine Liste von Namen benötigen, die verschiedene Elemente identifizieren , ist die Lösung von Mark Harrison (oben) großartig:Mit a
range
können Sie auch einen beliebigen Startwert festlegen :Wenn Sie außerdem benötigen, dass die Elemente zu einem Container gehören , binden Sie sie in eine Klasse ein:
Um das Aufzählungselement zu verwenden, müssten Sie jetzt den Containernamen und den Elementnamen verwenden:
Komplexe Aufzählung:
Für lange Listen von Aufzählungen oder kompliziertere Verwendungen von Aufzählungen reichen diese Lösungen nicht aus. Sie können sich das Rezept von Will Ware zur Simulation von Aufzählungen in Python ansehen, das im Python-Kochbuch veröffentlicht wurde . Eine Online-Version davon finden Sie hier .
Mehr Info:
PEP 354: Aufzählungen in Python enthalten die interessanten Details eines Vorschlags für eine Aufzählung in Python und warum er abgelehnt wurde.
quelle
range
Sie das erste Argument weglassen, wenn es 0 istmy_enum = dict(map(reversed, enumerate(str.split('Item0 Item1 Item2'))))
. Dannmy_enum
kann bei der Suche verwendet werden, zBmy_enum['Item0']
kann ein Index in eine Sequenz sein. Möglicherweise möchten Sie das Ergebnis vonstr.split
in eine Funktion einschließen, die eine Ausnahme auslöst, wenn Duplikate vorhanden sind.Flag1, Flag2, Flag3 = [2**i for i in range(3)]
Das typsichere Enum-Muster, das in Java vor JDK 5 verwendet wurde, bietet eine Reihe von Vorteilen. Ähnlich wie in Alexandru's Antwort erstellen Sie eine Klasse und Felder auf Klassenebene sind die Aufzählungswerte. Die Aufzählungswerte sind jedoch eher Instanzen der Klasse als kleine Ganzzahlen. Dies hat den Vorteil, dass Ihre Enum-Werte nicht versehentlich mit kleinen Ganzzahlen verglichen werden. Sie können steuern, wie sie gedruckt werden, beliebige Methoden hinzufügen, wenn dies nützlich ist, und mithilfe von isinstance Aussagen treffen:
Ein kürzlich veröffentlichter Thread zu Python-Dev wies darauf hin, dass es einige Enum-Bibliotheken in freier Wildbahn gibt, darunter:
quelle
Eine Enum-Klasse kann ein Einzeiler sein.
Verwendung (Vorwärts- und Rückwärtssuche, Schlüssel, Werte, Elemente usw.)
quelle
in
Schlüsselwort verwenden, um nach ordentlichen Mitgliedern zu suchen. Anwendungsbeispiel:'Claimed' in Enum(['Unclaimed', 'Claimed'])
Also stimme ich zu. Lassen Sie uns die Typensicherheit in Python nicht erzwingen, aber ich möchte mich vor dummen Fehlern schützen. Was denken wir darüber?
Es hält mich von Wertkollisionen bei der Definition meiner Aufzählungen ab.
Es gibt noch einen weiteren praktischen Vorteil: wirklich schnelle Reverse-Lookups:
quelle
Animal = Enum('horse', 'dog', 'cat')
. Ich fange auch den ValueError in getattr ab, wenn ein Element in self.values fehlt. Es scheint besser, stattdessen einen AttributeError mit der angegebenen Namenszeichenfolge auszulösen. Aufgrund meiner begrenzten Kenntnisse in diesem Bereich konnte ich die Metaklasse in Python 2.7 nicht zum Laufen bringen, aber meine benutzerdefinierte Enum-Klasse funktioniert problemlos mit direkten Instanzmethoden.Python hat kein eingebautes Äquivalent zu
enum
und andere Antworten haben Ideen für die Implementierung Ihrer eigenen (Sie könnten auch an der Over-the-Top-Version im Python-Kochbuch interessiert sein ).In Situationen, in denen ein
enum
in C erforderlich ist , verwende ich normalerweise nur einfache Zeichenfolgen : Aufgrund der Art und Weise, wie Objekte / Attribute implementiert werden, ist (C) Python so optimiert, dass es ohnehin sehr schnell mit kurzen Zeichenfolgen arbeitet Die Verwendung von Ganzzahlen ist kein wirklicher Leistungsvorteil. Um Tippfehler / ungültige Werte zu vermeiden, können Sie an ausgewählten Stellen Schecks einfügen.(Ein Nachteil gegenüber der Verwendung einer Klasse besteht darin, dass Sie den Vorteil der automatischen Vervollständigung verlieren.)
quelle
Am 10.05.2013 stimmte Guido zu, PEP 435 in die Python 3.4-Standardbibliothek aufzunehmen. Dies bedeutet, dass Python endlich Unterstützung für Aufzählungen hat!
Für Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 und 2.4 ist ein Backport verfügbar. Es ist auf Pypi als enum34 .
Erklärung:
Darstellung:
Wiederholung:
Programmatischer Zugriff:
Weitere Informationen finden Sie im Vorschlag . Offizielle Unterlagen werden voraussichtlich bald folgen.
quelle
Ich definiere Enums in Python lieber so:
Es ist fehlerfreier als die Verwendung von Ganzzahlen, da Sie sich nicht darum kümmern müssen, dass die Ganzzahlen eindeutig sind (z. B. wenn Sie Dog = 1 und Cat = 1 sagen, werden Sie geschraubt).
Es ist fehlerfreier als die Verwendung von Zeichenfolgen, da Sie sich keine Gedanken über Tippfehler machen müssen (z. B. x == "catt" schlägt stillschweigend fehl, aber x == Animal.Catt ist eine Laufzeitausnahme).
quelle
Verwenden Sie es so:
Wenn Sie nur eindeutige Symbole möchten und sich nicht um die Werte kümmern, ersetzen Sie diese Zeile:
mit diesem:
quelle
enum(names)
zuenum(*names)
- dann könnte man die zusätzliche Klammer fallen , wenn Sie anrufen.Ab Python 3.4 wird es offizielle Unterstützung für Aufzählungen geben. Dokumentation und Beispiele finden Sie hier auf der Python 3.4-Dokumentationsseite .
quelle
Hmmm ... Ich nehme an, das, was einer Aufzählung am nächsten kommt, ist ein Wörterbuch, das entweder so definiert ist:
oder
Dann können Sie den symbolischen Namen für die Konstanten wie folgt verwenden:
Es gibt andere Optionen, wie eine Liste von Tupeln oder ein Tupel von Tupeln, aber das Wörterbuch ist die einzige, die Ihnen eine "symbolische" (konstante Zeichenfolge) Möglichkeit bietet, auf den Wert zuzugreifen.
Edit: Ich mag auch Alexandru's Antwort!
quelle
Eine weitere, sehr einfache Implementierung einer Enumeration in Python mit
namedtuple
:oder alternativ,
set
Dies ermöglicht wie die obige Methode, die Unterklassen umfasst , Folgendes:Hat aber mehr Flexibilität, da es unterschiedliche Schlüssel und Werte haben kann. Dies erlaubt
um wie erwartet zu handeln, wenn Sie die Version verwenden, die fortlaufende Zahlenwerte ausfüllt.
quelle
Was ich benutze:
Wie benutzt man:
Dies gibt Ihnen also ganzzahlige Konstanten wie state.PUBLISHED und die zwei Tupel, die Sie in Django-Modellen als Auswahl verwenden können.
quelle
Davidg empfiehlt die Verwendung von Diktaten. Ich würde noch einen Schritt weiter gehen und Sets verwenden:
Jetzt können Sie testen, ob ein Wert mit einem der Werte in der Menge wie folgt übereinstimmt:
Wie bei dF verwende ich normalerweise nur String-Konstanten anstelle von Enums.
quelle
Halte es einfach:
Dann:
quelle
Dies ist die beste, die ich je gesehen habe: "First Class Enums in Python"
http://code.activestate.com/recipes/413486/
Es gibt Ihnen eine Klasse, und die Klasse enthält alle Aufzählungen. Die Aufzählungen können miteinander verglichen werden, haben jedoch keinen bestimmten Wert. Sie können sie nicht als ganzzahligen Wert verwenden. (Ich habe mich zunächst dagegen gewehrt, weil ich an C-Enums gewöhnt bin, bei denen es sich um ganzzahlige Werte handelt. Wenn Sie es jedoch nicht als Ganzzahl verwenden können, können Sie es nicht versehentlich als Ganzzahl verwenden. Insgesamt denke ich, dass es ein Gewinn ist .) Jede Aufzählung ist ein eindeutiger Wert. Sie können Aufzählungen drucken, Sie können darüber iterieren, Sie können testen, ob ein Aufzählungswert "in" der Aufzählung ist. Es ist ziemlich vollständig und glatt.
Bearbeiten (cfi): Der obige Link ist nicht Python 3-kompatibel. Hier ist meine Portierung von enum.py zu Python 3:
quelle
.__int__()
Methode eine Ausnahme für eine Aufzählung auslösen. Aber es sollte einen Weg geben, den Wert herauszuholen. Und es sollte möglich sein, bestimmte ganzzahlige Werte zur Zeit der Klassendefinition festzulegen, damit Sie eine Aufzählung für Dinge wie die Konstanten imstat
Modul verwenden können.Ich hatte Gelegenheit, eine Enum-Klasse zu benötigen, um ein binäres Dateiformat zu dekodieren. Die Funktionen, die ich zufällig haben wollte, sind eine
repr
präzise Aufzählungsdefinition, die Möglichkeit, Instanzen der Aufzählung entweder durch einen ganzzahligen Wert oder eine Zeichenfolge frei zu erstellen, und eine nützliche Darstellung. Folgendes habe ich erreicht:Ein wunderliches Beispiel für die Verwendung:
Hauptmerkmale:
str()
,int()
undrepr()
alle erzeugen die nützlichsten Ausgabe möglich, jeweils der Name des enumartion, dessen ganzzahliger Wert und einem Ausdruck, Python auswertet auf die Aufzählung zurück.is
quelle
__instancecheck__
Methode definiert . Klassen sind keine Sammlungen von Instanzen, daher1 in Fruit
ist es absurd. Die verknüpfte Version unterstützt jedoch,isinstance(1, Fruit)
was in Bezug auf den Begriff der Klassen und Instanzen korrekter wäre.Der neue Standard in Python ist PEP 435 , daher wird in zukünftigen Versionen von Python eine Enum-Klasse verfügbar sein:
Um es jetzt zu verwenden, können Sie die ursprüngliche Bibliothek installieren , die das PEP motiviert hat:
Dann Sie es gemäß seiner Online-Anleitung verwenden :
quelle
Wenn Sie es benennen, ist dies Ihr Problem. Wenn Sie jedoch keine Objekte anstelle von Werten erstellen, können Sie Folgendes tun:
Wenn Sie andere hier angeordnete Implementierungen verwenden (in meinem Beispiel auch benannte Instanzen), müssen Sie sicherstellen, dass Sie niemals versuchen, Objekte aus verschiedenen Aufzählungen zu vergleichen. Denn hier ist eine mögliche Falle:
Huch!
quelle
Die Lösung von Alec Thomas (http://stackoverflow.com/a/1695250) gefällt mir sehr gut:
Es sieht elegant und sauber aus, aber es ist nur eine Funktion, die eine Klasse mit den angegebenen Attributen erstellt.
Mit einer kleinen Modifikation der Funktion können wir sie ein wenig "enumy" wirken lassen:
Dadurch wird eine Aufzählung basierend auf einem angegebenen Typ erstellt. Zusätzlich zum Gewähren des Attributzugriffs wie bei der vorherigen Funktion verhält es sich so, wie Sie es von einer Aufzählung in Bezug auf Typen erwarten würden. Es erbt auch die Basisklasse.
Zum Beispiel ganzzahlige Aufzählungen:
Eine weitere interessante Sache, die mit dieser Methode durchgeführt werden kann, ist das Anpassen eines bestimmten Verhaltens durch Überschreiben der integrierten Methoden:
quelle
Das Enum-Paket von PyPI bietet eine robuste Implementierung von Enums. Eine frühere Antwort erwähnte PEP 354; Dies wurde abgelehnt, aber der Vorschlag wurde umgesetzt http://pypi.python.org/pypi/enum .
Die Verwendung ist einfach und elegant:
quelle
Alexandru's Vorschlag, Klassenkonstanten für Enums zu verwenden, funktioniert ganz gut.
Ich möchte auch ein Wörterbuch für jeden Satz von Konstanten hinzufügen, um eine für Menschen lesbare Zeichenfolgendarstellung nachzuschlagen.
Dies dient zwei Zwecken: a) Es bietet eine einfache Möglichkeit, Ihre Aufzählung hübsch auszudrucken, und b) das Wörterbuch gruppiert die Konstanten logisch, damit Sie die Mitgliedschaft testen können.
quelle
Hier ist ein Ansatz mit verschiedenen Merkmalen, die ich wertvoll finde:
und verhindert vor allem Vergleiche zwischen Aufzählungen verschiedener Typen !
Basierend auf http://code.activestate.com/recipes/413486-first-class-enums-in-python .
Viele hier enthaltene Doktrinen veranschaulichen, was an diesem Ansatz anders ist.
quelle
Hier ist eine Variante der Lösung von Alec Thomas :
quelle
Diese Lösung ist eine einfache Möglichkeit, eine Klasse für die als Liste definierte Aufzählung abzurufen (keine lästigen Ganzzahlzuweisungen mehr):
enumeration.py:
example.py:
quelle
type(class_name, (object,), dict(...))
stattdessen verwenden?Während der ursprüngliche Enum-Vorschlag, PEP 354 , vor Jahren abgelehnt wurde, kommt er immer wieder auf. Eine Art Aufzählung sollte zu 3.2 hinzugefügt werden, aber sie wurde auf 3.3 zurückgeschoben und dann vergessen. Und jetzt gibt es einen PEP 435 , der für die Aufnahme in Python 3.4 vorgesehen ist. Die Referenzimplementierung von PEP 435 ist
flufl.enum
.Ab April 2013 scheint es einen allgemeinen Konsens zu geben, dass der Standardbibliothek in 3.4 etwas hinzugefügt werden sollte - solange sich die Leute darauf einigen können, was dieses "Etwas" sein soll. Das ist der schwierige Teil. Siehe die Threads, die hier und hier beginnen , und ein halbes Dutzend anderer Threads in den ersten Monaten des Jahres 2013.
In der Zwischenzeit werden jedes Mal eine Reihe neuer Designs und Implementierungen auf PyPI, ActiveState usw. angezeigt. Wenn Ihnen das FLUFL-Design nicht gefällt, versuchen Sie es mit einer PyPI-Suche .
quelle
Verwenden Sie Folgendes.
Ich habe das für die Auswahl des Django- Modells verwendet und es sieht sehr pythonisch aus. Es ist nicht wirklich eine Aufzählung, aber es macht den Job.
quelle