1141 Stimmen

Wie kann ich ein "Enum" in Python darstellen?

Ich bin hauptsächlich ein C#-Entwickler, aber ich arbeite derzeit an einem Projekt in Python.

Wie kann ich das Äquivalent einer Enum in Python darstellen?

2952voto

Alec Thomas Punkte 17213

Enums wurden zu Python 3.4 hinzugefügt, wie in PEP 435 . Es wurde auch schon zurückportiert nach 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 und 2.4 auf pypi.

Für fortgeschrittene Enum-Techniken versuchen Sie die Aenum-Bibliothek (2.7, 3.3+, gleicher Autor wie enum34 . Der Code ist nicht perfekt kompatibel zwischen py2 und py3, z.B. benötigen Sie __order__ in Python 2 ).

  • Zur Verwendung enum34 tun $ pip install enum34
  • Zu verwenden aenum tun $ pip install aenum

Installation von enum (ohne Zahlen) 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 gleichwertig:

class Animal(Enum):
    ant = 1
    bee = 2
    cat = 3
    dog = 4

In früheren Versionen war eine Möglichkeit, Enums zu erreichen:

def enum(**enums):
    return type('Enum', (), enums)

die wie folgt 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 leicht mit etwas wie diesem 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

Auf diese Weise kann eine Unterstützung für die Rückkonvertierung der Werte in Namen 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, was diesen Namen trägt, ist aber nützlich, um Ihre Enums in der Ausgabe darzustellen. Es wird ein KeyError wenn die umgekehrte Zuordnung nicht existiert. Mit dem ersten Beispiel:

>>> Numbers.reverse_mapping['three']
'THREE'

Wenn Sie MyPy verwenden, ist eine weitere Möglichkeit, "enums" auszudrücken, mit typing.Literal .

Zum Beispiel:

from typing import Literal #python >=3.8
from typing_extensions import Literal #python 2.7, 3.4-3.7

Animal = Literal['ant', 'bee', 'cat', 'dog']

def hello_animal(animal: Animal):
    print(f"hello {animal}")

hello_animal('rock') # error
hello_animal('bee') # passes

949voto

Alexandru Nedelcu Punkte 7914

Vor PEP 435 gab es in Python kein Äquivalent, aber man konnte sein eigenes implementieren.

Ich selbst halte es gerne einfach (ich habe einige schrecklich komplexe Beispiele im Netz gesehen), etwa so ...

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

In Python 3.4 ( PEP 435 ), können Sie Enum die Basisklasse. Dadurch erhalten Sie ein wenig zusätzliche Funktionalität, die im PEP beschrieben wird. Zum Beispiel unterscheiden sich Enum-Mitglieder von Integern, und sie bestehen aus einer name und eine value .

from enum import Enum

class Animal(Enum):
    DOG = 1
    CAT = 2

print(Animal.DOG)
# <Animal.DOG: 1>

print(Animal.DOG.value)
# 1

print(Animal.DOG.name)
# "DOG"

Wenn Sie die Werte nicht eintippen wollen, verwenden Sie die folgende Abkürzung:

class Animal(Enum):
    DOG, CAT = range(2)

Enum Implementierungen können in Listen umgewandelt werden und sind iterierbar . Die Reihenfolge ihrer Mitglieder ist die Reihenfolge der Deklaration und hat nichts mit ihren Werten zu tun. Zum Beispiel:

class Animal(Enum):
    DOG = 1
    CAT = 2
    COW = 0

list(Animal)
# [<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.COW: 0>]

[animal.value for animal in Animal]
# [1, 2, 0]

Animal.CAT in Animal
# True

353voto

shahjapan Punkte 12481

Hier ist eine Umsetzung:

class Enum(set):
    def __getattr__(self, name):
        if name in self:
            return name
        raise AttributeError

Hier ist seine Verwendung:

Animals = Enum(["DOG", "CAT", "HORSE"])

print(Animals.DOG)

221voto

Mark Harrison Punkte 281807

Wenn Sie die numerischen Werte benötigen, ist dies der schnellste Weg:

dog, cat, rabbit = range(3)

In Python 3.x können Sie auch einen Platzhalter mit Sternchen am Ende hinzufügen, der alle verbleibenden Werte des Bereichs aufnimmt, falls es Ihnen nichts ausmacht, Speicher zu verschwenden und nicht zählen zu können:

dog, cat, rabbit, horse, *_ = range(100)

141voto

Ashwin Nanjappa Punkte 72122

Welche Lösung für Sie die beste ist, hängt davon ab, welche Anforderungen Sie an Ihr gefälscht enum .

Einfache Aufzählung:

Wenn Sie die enum als nur eine Liste von Namen Identifizierung verschiedener Artikel die Lösung durch Mark Harrison (oben) ist großartig:

Pen, Pencil, Eraser = range(0, 3)

Mit einer range ermöglicht es Ihnen auch, beliebige Startwert :

Pen, Pencil, Eraser = range(9, 12)

Wenn Sie zusätzlich zu den oben genannten Punkten verlangen, dass die Gegenstände zu einem Container und betten sie dann in eine Klasse ein:

class Stationery:
    Pen, Pencil, Eraser = range(0, 3)

Um das Aufzählungselement zu verwenden, müssen Sie nun den Containernamen und den Elementnamen verwenden:

stype = Stationery.Pen

Komplexe Aufzählung:

Für lange Listen von enum oder kompliziertere Verwendungen von enum reichen diese Lösungen nicht aus. Sie können sich an das Rezept von Will Ware für Aufzählungen in Python simulieren veröffentlicht in der Python-Kochbuch . Eine Online-Version davon ist verfügbar ici .

Mehr Informationen:

PEP 354: Aufzählungen in Python hat die interessanten Details eines Vorschlags für enum in Python und warum er abgelehnt wurde.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X