¿Cómo puedo representar un 'Enum' en Python?

Resuelto John Rutherford asked hace 16 años • 43 respuestas

Soy principalmente desarrollador de C#, pero actualmente estoy trabajando en un proyecto en Python.

¿Cómo puedo representar el equivalente de un Enum en Python?

John Rutherford avatar Aug 31 '08 22:08 John Rutherford
Aceptado

Se han agregado enumeraciones a Python 3.4 como se describe en PEP 435 . También se ha realizado una copia de seguridad a 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 y 2.4 en pypi.

Para técnicas Enum más avanzadas, pruebe la biblioteca aenum (2.7, 3.3+, el mismo autor que enum34. El código no es perfectamente compatible entre py2 y py3, por ejemplo, lo necesitará __order__en python 2 ).

  • Para usar enum34, haz$ pip install enum34
  • Para usar aenum, haz$ pip install aenum

La instalación enum(sin números) instalará una versión completamente diferente e incompatible.


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)

o equivalente:

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

En versiones anteriores, una forma de realizar enumeraciones es:

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

que se usa así:

>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'

También puedes admitir fácilmente la enumeración automática con algo como esto:

def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    return type('Enum', (), enums)

y usado así:

>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1

Se puede agregar soporte para convertir los valores nuevamente a nombres de esta manera:

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)

Esto sobrescribe cualquier cosa con ese nombre, pero es útil para representar sus enumeraciones en la salida. Lanzará un KeyErrorsi el mapeo inverso no existe. Con el primer ejemplo:

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

Si está utilizando MyPy, otra forma de expresar "enumeraciones" es con typing.Literal.

Por ejemplo:

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

Alec Thomas avatar Nov 08 '2009 03:11 Alec Thomas

Antes de PEP 435, Python no tenía un equivalente pero podías implementar el tuyo propio.

A mí me gusta mantenerlo simple (he visto algunos ejemplos terriblemente complejos en la red), algo como esto...

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

En Python 3.4 ( PEP 435 ), puedes hacer de Enum la clase base. Esto le brinda un poco de funcionalidad adicional, descrita en el PEP. Por ejemplo, los miembros de enum son distintos de los números enteros y están compuestos por a namey a 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"

Si no desea escribir los valores, utilice el siguiente acceso directo:

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

Enumlas implementaciones se pueden convertir en listas y son iterables . El orden de sus miembros es el orden de declaración y no tiene nada que ver con sus valores. Por ejemplo:

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
Jundiaius avatar Aug 31 '2008 16:08 Jundiaius

Aquí hay una implementación:

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

Aquí está su uso:

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

print(Animals.DOG)
shahjapan avatar Feb 02 '2010 07:02 shahjapan