# `enum` — Soporte para enumeraciones

Nuevo en la versión 3.4.

Código fuente: Lib/enum.py

Una enumeración es un conjunto de nombres simbólicos (miembros) vinculados a valores únicos y constantes. Dentro de una enumeración, los miembros se pueden comparar por identidad, y la enumeración en sí se puede iterar.

Nota

Case of Enum Members

Because Enums are used to represent constants we recommend using UPPER_CASE names for enum members, and will be using that style in our examples.

## Contenido del Módulo

Este módulo define cuatro clases de enumeración que se pueden usar para definir conjuntos únicos de nombres y valores: `Enum`, `IntEnum`, `Flag`, and `IntFlag`. También define un decorador, `unique()`, y un ayudante, `auto`.

class `enum.``Enum`

  Clase base para crear constantes enumeradas. Consulte la sección API Funcional para obtener una sintaxis de construcción alternativa.

class `enum.``IntEnum`

  Clase base para crear constantes enumeradas que también son sub clases de `int`.

class `enum.``IntFlag`

  Clase base para crear constantes enumeradas que se pueden combinar usando los operadores bitwise sin perder su membresía `IntFlag`. Los miembros de `IntFlag` también son subclases de `int`.

class `enum.``Flag`

  Clase base para crear constantes enumeradas que se pueden combinar utilizando las operaciones bitwise sin perder su membresía `Flag`.

`enum.``unique`()

  El decorador de clase Enum que garantiza que solo un nombre esté vinculado a cualquier valor.

class `enum.``auto`

  Las instancias se reemplazan con un valor apropiado para los miembros de Enum. El valor inicial comienza en 1.

Nuevo en la versión 3.6: `Flag`, `IntFlag`, `auto`

## Creando un Enum

Las enumeraciones son creadas usando la sintaxis `class`, lo que las hace de fácil lectura y escritura. Un método de creación alternativo se describe en API Funcional. Para definir una enumeración, hacer una subclase `Enum` de la siguiente manera:

    >>> from enum import Enum
    >>> class Color(Enum):
    ...     RED = 1
    ...     GREEN = 2
    ...     BLUE = 3
    ...

Nota

Valores de miembros de Enum

Los valores de los miembros pueden ser cualquier cosa: `int`, `str`, etc.. Si el valor exacto no es importante, puede usar instancias `auto` y se elegirá un valor apropiado para usted. Se debe tener cuidado si se mezcla `auto` con otros valores.

Nota

Nomenclatura

- La clase `Color` es una enumeración (o enum)

- Los atributos `Color.RED`, `Color.GREEN`, etc., son miembros de enumeración (o miembros de enum) y son funcionalmente constantes.

- Los miembros de la enumeración tienen nombres y valores (el nombre de `Color.RED` es `ROJO`, el valor de `Color.BLUE` es `3`, etc. )

Nota

Aunque usamos la sintaxis `class` para crear Enums, los Enums no son clases normales de Python. Consulte ¿En qué se diferencian las enumeraciones? para obtener más detalles.

Los miembros de la enumeración tienen representaciones de cadenas legibles para humanos

    >>> print(Color.RED)
    Color.RED

…mientras que su `repr` tiene más información

    >>> print(repr(Color.RED))
    <Color.RED: 1>

El tipo de un miembro de enumeración es la enumeración a la que pertenece:

    >>> type(Color.RED)
    <enum 'Color'>
    >>> isinstance(Color.GREEN, Color)
    True
    >>>

Los miembros de Enum también tienen una propiedad que contiene solo su nombre del elemento

    >>> print(Color.RED.name)
    RED

Las enumeraciones soportan iteración, en orden de definición:

    >>> class Shake(Enum):
    ...     VANILLA = 7
    ...     CHOCOLATE = 4
    ...     COOKIES = 9
    ...     MINT = 3
    ...
    >>> for shake in Shake:
    ...     print(shake)
    ...
    Shake.VANILLA
    Shake.CHOCOLATE
    Shake.COOKIES
    Shake.MINT

Los miembros de la enumeración son hasheables, por lo que pueden usarse en diccionarios y conjuntos:

    >>> apples = {}
    >>> apples[Color.RED] = 'red delicious'
    >>> apples[Color.GREEN] = 'granny smith'
    >>> apples == {Color.RED: 'red delicious', Color.GREEN: 'granny smith'}
    True

## Acceso programático a los miembros de la enumeración y sus atributos

A veces es útil acceder a los miembros en enumeraciones mediante programación (es decir, situaciones en las que `Color.RED` no funcionará porque no se conoce el color exacto al momento de escribir el programa). `Enum` permite dicho acceso:

    >>> Color(1)
    <Color.RED: 1>
    >>> Color(3)
    <Color.BLUE: 3>

Si desea acceder a los miembros de enumeración por nombre, use el acceso a elementos:

    >>> Color['RED']
    <Color.RED: 1>
    >>> Color['GREEN']
    <Color.GREEN: 2>

Si tiene un miembro enum y necesita su `name` o `value`:

    >>> member = Color.RED
    >>> member.name
    'RED'
    >>> member.value
    1

## Duplicando miembros y valores enum

Tener dos miembros enum con el mismo nombre no es válido:

    >>> class Shape(Enum):
    ...     SQUARE = 2
    ...     SQUARE = 3
    ...
    Traceback (most recent call last):
    ...
    TypeError: Attempted to reuse key: 'SQUARE'

Sin embargo, se permite que dos miembros enum tengan el mismo valor. Dado que dos miembros A y B tienen el mismo valor (y A se definió primero), B es un alias de A. La búsqueda por valor del valor de A y B retornará A. La búsqueda por nombre de B también retornará A:

    >>> class Shape(Enum):
    ...     SQUARE = 2
    ...     DIAMOND = 1
    ...     CIRCLE = 3
    ...     ALIAS_FOR_SQUARE = 2
    ...
    >>> Shape.SQUARE
    <Shape.SQUARE: 2>
    >>> Shape.ALIAS_FOR_SQUARE
    <Shape.SQUARE: 2>
    >>> Shape(2)
    <Shape.SQUARE: 2>

Nota

Intentar crear un miembro con el mismo nombre que un atributo ya definido (otro miembro, un método, etc.) o intentar crear un atributo con el mismo nombre que un miembro no está permitido.

## Garantizando valores de enumeración únicos

Por defecto, las enumeraciones permiten múltiples nombres como alias para el mismo valor. Cuando no se desea este comportamiento, se puede usar el siguiente decorador para garantizar que cada valor se use solo una vez en la enumeración:

`@``enum.``unique`

Un decorador de `class` específicamente para enumeraciones. Busca una enumeración `__members__` reuniendo cualquier alias que encuentre; si no se encuentra alguno se genera un `ValueError` con los detalles:

    >>> from enum import Enum, unique
    >>> @unique
    ... class Mistake(Enum):
    ...     ONE = 1
    ...     TWO = 2
    ...     THREE = 3
    ...     FOUR = 3
    ...
    Traceback (most recent call last):
    ...
    ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE

## Usando valores automáticos

Si el valor exacto no es importante, puede usar `auto`:

    >>> from enum import Enum, auto
    >>> class Color(Enum):
    ...     RED = auto()
    ...     BLUE = auto()
    ...     GREEN = auto()
    ...
    >>> list(Color)
    [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

Los valores se eligen por `_generate_next_value_()`, que se puede invalidar:

    >>> class AutoName(Enum):
    ...     def _generate_next_value_(name, start, count, last_values):
    ...         return name
    ...
    >>> class Ordinal(AutoName):
    ...     NORTH = auto()
    ...     SOUTH = auto()
    ...     EAST = auto()
    ...     WEST = auto()
    ...
    >>> list(Ordinal)
    [<Ordinal.NORTH: 'NORTH'>, <Ordinal.SOUTH: 'SOUTH'>, <Ordinal.EAST: 'EAST'>, <Ordinal.WEST: 'WEST'>]

Nota

The goal of the default `_generate_next_value_()` method is to provide the next `int` in sequence with the last `int` provided, but the way it does this is an implementation detail and may change.

Nota

The `_generate_next_value_()` method must be defined before any members.

## Iteración

Iterar sobre los miembros de una enumeración no proporciona los alias:

    >>> list(Shape)
    [<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]

El atributo especial `__members__` es una asignación ordenada de solo lectura de nombres a miembros. Incluye todos los nombres definidos en la enumeración, incluidos los alias:

    >>> for name, member in Shape.__members__.items():
    ...     name, member
    ...
    ('SQUARE', <Shape.SQUARE: 2>)
    ('DIAMOND', <Shape.DIAMOND: 1>)
    ('CIRCLE', <Shape.CIRCLE: 3>)
    ('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)

El atributo `__members__` se puede usar para el acceso programático detallado a los miembros de la enumeración. Por ejemplo, encontrar todos los alias:

    >>> [name for name, member in Shape.__members__.items() if member.name != name]
    ['ALIAS_FOR_SQUARE']

## Comparaciones

Los miembros de la enumeración se comparan por identidad:

    >>> Color.RED is Color.RED
    True
    >>> Color.RED is Color.BLUE
    False
    >>> Color.RED is not Color.BLUE
    True

Las comparaciones ordenadas entre valores de enumeración no son soportadas. Los miembros de Enum no son enteros (pero vea IntEnum a continuación):

    >>> Color.RED < Color.BLUE
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: '<' not supported between instances of 'Color' and 'Color'

Aunque, las comparaciones de igualdad se definen:

    >>> Color.BLUE == Color.RED
    False
    >>> Color.BLUE != Color.RED
    True
    >>> Color.BLUE == Color.BLUE
    True

Las comparaciones con valores de no enumeración siempre se compararán no iguales (de nuevo, `IntEnum` fue diseñado explícitamente para comportarse de manera diferente, ver más abajo):

    >>> Color.BLUE == 2
    False

## Miembros permitidos y atributos de enumeraciones

Los ejemplos anteriores usan números enteros para los valores de enumeración. El uso de enteros es breve y útil (y lo proporciona de forma predeterminada la API Funcional), pero no se aplica estrictamente. En la gran mayoría de los casos de uso, a uno no le importa cuál es el valor real de una enumeración. Pero si el valor es importante, las enumeraciones pueden tener valores arbitrarios.

Las enumeraciones son clases de Python y pueden tener métodos y métodos especiales como de costumbre. Si tenemos esta enumeración

    >>> class Mood(Enum):
    ...     FUNKY = 1
    ...     HAPPY = 3
    ...
    ...     def describe(self):
    ...         # self is the member here
    ...         return self.name, self.value
    ...
    ...     def __str__(self):
    ...         return 'my custom str! {0}'.format(self.value)
    ...
    ...     @classmethod
    ...     def favorite_mood(cls):
    ...         # cls here is the enumeration
    ...         return cls.HAPPY
    ...

Después:

    >>> Mood.favorite_mood()
    <Mood.HAPPY: 3>
    >>> Mood.HAPPY.describe()
    ('HAPPY', 3)
    >>> str(Mood.FUNKY)
    'my custom str! 1'

Las reglas para lo que está permitido son las siguientes: los nombres que comienzan y terminan con un solo guión bajo están reservados por enum y no se pueden usar; todos los demás atributos definidos dentro de una enumeración se convertirán en miembros de esta enumeración, con la excepción de métodos especiales (`__str__()`, `__add__()`, etc.), descriptores (los métodos también son descriptores) y nombres de variables listado en `_ignore_`.

Nota: si tu enumeración define `__new__()` y/o `__init__()`, los valores que se hayan dado al miembro enum se pasarán a esos métodos. Ver Planeta para un ejemplo.

## Subclases restringidas de Enum

Una nueva clase `Enum` debe tener una clase base Enum, hasta un tipo de datos concreto, y tantas clases mixin basadas en `object` como sean necesarias. El orden de estas clases base es:

    class EnumName([mix-in, ...,] [data-type,] base-enum):
        pass

Además, la subclasificación de una enumeración solo está permitida si la enumeración no define ningún miembro. Entonces esto está prohibido:

    >>> class MoreColor(Color):
    ...     PINK = 17
    ...
    Traceback (most recent call last):
    ...
    TypeError: Cannot extend enumerations

Pero esto es permitido:

    >>> class Foo(Enum):
    ...     def some_behavior(self):
    ...         pass
    ...
    >>> class Bar(Foo):
    ...     HAPPY = 1
    ...     SAD = 2
    ...

Permitir la subclasificación de enumeraciones que definen miembros conduciría a una violación de algunos invariantes importantes de tipos e instancias. Por otro lado, tiene sentido permitir compartir un comportamiento común entre un grupo de enumeraciones. (Ver OrderedEnum para un ejemplo.)

## Serialización

Las enumeraciones se pueden serializar y desempaquetar:

    >>> from test.test_enum import Fruit
    >>> from pickle import dumps, loads
    >>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
    True

Se aplican las restricciones habituales para la serialización (pickling): las enum seleccionables se deben definir en el nivel superior de un módulo, ya que el desempaquetado requiere que sean importables desde ese módulo.

Nota

Con la versión 4 del protocolo de serialización (pickle), es posible seleccionar fácilmente las enumeraciones anidadas en otras clases.

Es posible modificar la forma en que los miembros de Enum se serializan/desempaquetan definiendo `__reduce_ex__()` en la clase de enumeración.

## API Funcional

La clase `Enum` es invocable, proporcionando la siguiente API funcional:

    >>> Animal = Enum('Animal', 'ANT BEE CAT DOG')
    >>> Animal
    <enum 'Animal'>
    >>> Animal.ANT
    <Animal.ANT: 1>
    >>> Animal.ANT.value
    1
    >>> list(Animal)
    [<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]

La semántica de esta API se parece a `namedtuple`. El primer argumento de la llamada a `Enum` es el nombre de la enumeración.

El segundo argumento es la fuente de los nombres de los miembros de la enumeración. Puede se una cadena de nombres separados por espacios en blanco, una secuencia de 2 tuplas con pares de clave/valor, o un mapeo de nombres y valores (ej. diccionario). Las últimas dos opciones permiten asignar valores arbitrarios a las enumeraciones; los otros asignan automáticamente enteros crecientes comenzando con 1 (use el parámetros `start` para especificar un valor de inicio diferente). Se regresa una nueva clase derivada de `Enum`. En otras palabras, la asignación de arriba `Animal` es equivalente a:

    >>> class Animal(Enum):
    ...     ANT = 1
    ...     BEE = 2
    ...     CAT = 3
    ...     DOG = 4
    ...

La razón por la que el valor predeterminado es `1` como numero inicial y no `0` es que `0` es `False` en sentido booleano, pero todos los miembros enum evalúan como `True`.

Las enumeraciones serializadas creadas con la API funcional pueden ser complicadas ya que los detalles de implementación de la pila se usan para tratar de averiguar en qué módulo se está creando la enumeración (ej. fallará si usa una función de utilidad en un módulo separado, y también puede no funcionar en IronPython o Jython). La solución es especificar el nombre del módulo explícitamente de la siguiente manera:

    >>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)

Advertencia

Si no se suministra un `module`, y Enum no puede determinar que es, los miembros del nuevo Enum no se podrán desempaquetar; para mantener los errores más cerca de la fuente, la serialización se deshabilitará.

El nuevo protocolo 4 de serialización también, en ciertas circunstancias, se basa en `__qualname__` se establece en la ubicación donde la serialización podrá encontrar la clase. Por ejemplo, si la clase se hizo disponible en la clase SomeData en el campo global:

    >>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')

La firma completa es:

    Enum(value='NewEnumName', names=<...>, *, module='...', qualname='...', type=<mixed-in class>, start=1)

valor

  Lo que la nueva clase Enum registrará como su nombre.

nombres

  Los miembros de Enum. Esto puede ser un espacio en blanco o una cadena separada por comas (los valores empezarán en 1 a menos que se especifique lo contrario):

      'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'

  o un iterador de nombres:

      ['RED', 'GREEN', 'BLUE']

  o un iterador de pares(nombre,valor):

      [('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]

  o un mapeo:

      {'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}

módulo

  nombre del módulo donde se puede encontrar la nueva clase Enum.

qualname

  donde en el módulo se puede encontrar la nueva clase Enum.

tipo

  escriba para mezclar en la nueva clase Enum.

inicio

  número para comenzar a contar sí solo se pasan nombres.

Distinto en la versión 3.5: Se agregó el parámetro start.

## Enumeraciones derivadas

### IntEnum

La primera variación de `Enum` que se proporciona también es una subclase de `int`. Los miembros de `IntEnum` se pueden comparar con enteros; por extensión, las enumeraciones enteras de diferentes tipos también se pueden comparar entre sí:

    >>> from enum import IntEnum
    >>> class Shape(IntEnum):
    ...     CIRCLE = 1
    ...     SQUARE = 2
    ...
    >>> class Request(IntEnum):
    ...     POST = 1
    ...     GET = 2
    ...
    >>> Shape == 1
    False
    >>> Shape.CIRCLE == 1
    True
    >>> Shape.CIRCLE == Request.POST
    True

Sin embargo, todavía no se pueden comparar con las enumeraciones estándar `Enum`:

    >>> class Shape(IntEnum):
    ...     CIRCLE = 1
    ...     SQUARE = 2
    ...
    >>> class Color(Enum):
    ...     RED = 1
    ...     GREEN = 2
    ...
    >>> Shape.CIRCLE == Color.RED
    False

los valores `IntEnum` se comportan como enteros en otras maneras que esperarías:

    >>> int(Shape.CIRCLE)
    1
    >>> ['a', 'b', 'c'][Shape.CIRCLE]
    'b'
    >>> [i for i in range(Shape.SQUARE)]
    [0, 1]

### IntFlag

La siguiente variación de `Enum` proporcionada, `IntFlag`, también se basa en `int`. La diferencia es que los miembros `IntFlag` se pueden combinar usando los operadores (&, |, ^, ~) y el resultado es un miembro `IntFlag`. Sin embargo, como su nombre lo indica, los miembros de `IntFlag` también son subclase `int` y pueden usarse siempre que `int` se use. Cualquier operación en un miembro `IntFlag` además de las operaciones de bit perderán la membresía `IntFlag`.

Nuevo en la versión 3.6.

Clase muestra `IntFlag`:

    >>> from enum import IntFlag
    >>> class Perm(IntFlag):
    ...     R = 4
    ...     W = 2
    ...     X = 1
    ...
    >>> Perm.R | Perm.W
    <Perm.R|W: 6>
    >>> Perm.R + Perm.W
    6
    >>> RW = Perm.R | Perm.W
    >>> Perm.R in RW
    True

También es posible nombrar las combinaciones:

    >>> class Perm(IntFlag):
    ...     R = 4
    ...     W = 2
    ...     X = 1
    ...     RWX = 7
    >>> Perm.RWX
    <Perm.RWX: 7>
    >>> ~Perm.RWX
    <Perm.-8: -8>

Otra diferencia importante entre `IntFlag` y `Enum` es que si no hay banderas establecidas (el valor es 0), su evaluación booleana es `False`:

    >>> Perm.R & Perm.X
    <Perm.0: 0>
    >>> bool(Perm.R & Perm.X)
    False

Porque los miembros `IntFlag` también son subclases de `int` se pueden combinar con ellos:

    >>> Perm.X | 8
    <Perm.8|X: 9>

### Bandera

La última variación es `Flag`. Al igual que `IntFlag`, `Flag` los miembros se pueden combinar usando los operadores (&, |, ^, ~). A diferencia de `IntFlag`, no pueden combinar ni comparar con ninguna otra enumeración `Flag`, ni con `int`. Es posible especificar los valores directamente, se recomienda usar `auto` como el valor y dejar que `Flag` seleccione el valor apropiado.

Nuevo en la versión 3.6.

Al igual que `IntFlag`, si una combinación de miembros `Flag` resultan en que no se establezcan banderas, la evaluación booleana es `False`:

    >>> from enum import Flag, auto
    >>> class Color(Flag):
    ...     RED = auto()
    ...     BLUE = auto()
    ...     GREEN = auto()
    ...
    >>> Color.RED & Color.GREEN
    <Color.0: 0>
    >>> bool(Color.RED & Color.GREEN)
    False

Las banderas individuales deben tener valores que sean potencias de dos (1, 2, 4, 8, …), mientras que las combinaciones de banderas no:

    >>> class Color(Flag):
    ...     RED = auto()
    ...     BLUE = auto()
    ...     GREEN = auto()
    ...     WHITE = RED | BLUE | GREEN
    ...
    >>> Color.WHITE
    <Color.WHITE: 7>

Dar un nombre a la condición «sin banderas establecidas» no cambia su valor booleano:

    >>> class Color(Flag):
    ...     BLACK = 0
    ...     RED = auto()
    ...     BLUE = auto()
    ...     GREEN = auto()
    ...
    >>> Color.BLACK
    <Color.BLACK: 0>
    >>> bool(Color.BLACK)
    False

Nota

Para la mayoría del código nuevo, `Enum` y `Flag` son muy recomendables, ya que `IntEnum` y `IntFlag` rompen algunas promesas semánticas de una enumeración (al ser comparables con enteros, y por transitividad a otras enumeraciones no relacionadas). `IntEnum` y `IntFlag` deben usarse solo en casos donde `Enum` y `Flag` no son suficientes: por ejemplo, cuando las constantes enteras se reemplazan por enumeraciones, o por interoperabilidad con otros sistemas.

### Otros

Mientras que `IntEnum` es parte del módulo `enum`, sería muy simple de implementar de forma independiente:

    class IntEnum(int, Enum):
        pass

Esto demuestra que similares pueden ser las enumeraciones derivadas; por ejemplo una `StrEnum` que se mezcla en `str` en lugar de `int`.

Algunas reglas:

1. Al subclasificar `Enum`, los tipos mixtos deben aparecer antes `Enum` en la secuencia de bases, como en el ejemplo anterior `IntEnum`.

2. Mientras que `Enum` puede tener miembros de cualquier tipo, una vez que se mezcle tipos adicionales, todos los miembros deben de tener los valores de ese tipo, ej. `int` de arriba. Esta restricción no se aplica a las mezclas que solo agregan métodos y no especifican otro tipo de datos como `int` o `str`.

3. Cuando se mezcla otro tipo de datos, el atributo `value` no es el mismo que el mismo miembro enum, aunque es equivalente y se comparará igual.

4. Formato %-style: %s y %r llaman, respectivamente, a `__str__()` y `__repr__()` de la clase `Enum`; otros códigos (como &i o %h para IntEnum) tratan al miembro enum como su tipo mixto.

5. Formatted string literals, `str.format()`, and `format()` will use the mixed-in type’s `__format__()` unless `__str__()` or `__format__()` is overridden in the subclass, in which case the overridden methods or `Enum` methods will be used. Use the !s and !r format codes to force usage of the `Enum` class’s `__str__()` and `__repr__()` methods.

## Cuándo usar `__new__()` contra `__init__()`

`__new__()` debe usarse siempre que desee personalizar el valor del miembro real `Emum`. Cualquier otra modificación puede ir en `__new__()` o `__init__()`, prefiriendo siempre `__init__()`.

Por ejemplo, si desea pasar varios elementos al constructor, pero solo desea que uno de ellos sea el valor:

    >>> class Coordinate(bytes, Enum):
    ...     """
    ...     Coordinate with binary codes that can be indexed by the int code.
    ...     """
    ...     def __new__(cls, value, label, unit):
    ...         obj = bytes.__new__(cls, [value])
    ...         obj._value_ = value
    ...         obj.label = label
    ...         obj.unit = unit
    ...         return obj
    ...     PX = (0, 'P.X', 'km')
    ...     PY = (1, 'P.Y', 'km')
    ...     VX = (2, 'V.X', 'km/s')
    ...     VY = (3, 'V.Y', 'km/s')
    ...

    >>> print(Coordinate['PY'])
    Coordinate.PY

    >>> print(Coordinate(3))
    Coordinate.VY

## Ejemplos interesantes

Si bien se espera que `Enum`, `IntEnum`, `IntFlag`, y `Flag` cubran la mayoría de los casos de uso, no pueden cubrirlos a todos. Aquí hay recetas para algunos tipos diferentes de enumeraciones que puede usarse directamente, o como ejemplos para crear los propios.

### Omitir valores

En muchos casos de uso, a uno no le importa cuál es el valor real de una enumeración. Hay varias formas de definir este tipo de enumeración simple:

- use instancias de `auto` para el valor

- use instancias de `object` como el valor

- use a descriptive string as the value

- use una tupla como valor y un `__new__()` personalizado para reemplazar la tupla con un valor `int`

El uso de cualquiera de estos métodos significa para el usuario que estos valores no son importantes y también permite agregar, eliminar o reordenar miembros sin tener que volver a numerar los miembros restantes.

Cualquiera que sea el método que elijas, debe proporcionar un `repr()` que también oculte el valor (sin importancia):

    >>> class NoValue(Enum):
    ...     def __repr__(self):
    ...         return '<%s.%s>' % (self.__class__.__name__, self.name)
    ...

#### Usando `auto`

Usando `auto` se vería como:

    >>> class Color(NoValue):
    ...     RED = auto()
    ...     BLUE = auto()
    ...     GREEN = auto()
    ...
    >>> Color.GREEN
    <Color.GREEN>

#### Usando `object`

Usando `object` se vería como:

    >>> class Color(NoValue):
    ...     RED = object()
    ...     GREEN = object()
    ...     BLUE = object()
    ...
    >>> Color.GREEN
    <Color.GREEN>

#### Usando una cadena descriptiva

Usar una cadena como valor se vería así:

    >>> class Color(NoValue):
    ...     RED = 'stop'
    ...     GREEN = 'go'
    ...     BLUE = 'too fast!'
    ...
    >>> Color.GREEN
    <Color.GREEN>
    >>> Color.GREEN.value
    'go'

#### Usando `__new__()` personalizados

Usando una numeración automática `__new__()` se vería como:

    >>> class AutoNumber(NoValue):
    ...     def __new__(cls):
    ...         value = len(cls.__members__) + 1
    ...         obj = object.__new__(cls)
    ...         obj._value_ = value
    ...         return obj
    ...
    >>> class Color(AutoNumber):
    ...     RED = ()
    ...     GREEN = ()
    ...     BLUE = ()
    ...
    >>> Color.GREEN
    <Color.GREEN>
    >>> Color.GREEN.value
    2

To make a more general purpose `AutoNumber`, add `*args` to the signature:

    >>> class AutoNumber(NoValue):
    ...     def __new__(cls, *args):      # this is the only change from above
    ...         value = len(cls.__members__) + 1
    ...         obj = object.__new__(cls)
    ...         obj._value_ = value
    ...         return obj
    ...

Then when you inherit from `AutoNumber` you can write your own `__init__` to handle any extra arguments:

    >>> class Swatch(AutoNumber):
    ...     def __init__(self, pantone='unknown'):
    ...         self.pantone = pantone
    ...     AUBURN = '3497'
    ...     SEA_GREEN = '1246'
    ...     BLEACHED_CORAL = () # New color, no Pantone code yet!
    ...
    >>> Swatch.SEA_GREEN
    <Swatch.SEA_GREEN: 2>
    >>> Swatch.SEA_GREEN.pantone
    '1246'
    >>> Swatch.BLEACHED_CORAL.pantone
    'unknown'

Nota

El método `__new__()`, está definido, se usa durante la creación de los miembros Enum; se remplaza entonces por el Enum `__new__()` que se utiliza después de la creación de la clase para buscar miembros existentes.

### OrderedEnum

Una enumeración ordenada que no se basa en `IntEnum` y, por lo tanto mantiene los invariantes normales de `Enum` (como no ser comparables con otras enumeraciones):

    >>> class OrderedEnum(Enum):
    ...     def __ge__(self, other):
    ...         if self.__class__ is other.__class__:
    ...             return self.value >= other.value
    ...         return NotImplemented
    ...     def __gt__(self, other):
    ...         if self.__class__ is other.__class__:
    ...             return self.value > other.value
    ...         return NotImplemented
    ...     def __le__(self, other):
    ...         if self.__class__ is other.__class__:
    ...             return self.value <= other.value
    ...         return NotImplemented
    ...     def __lt__(self, other):
    ...         if self.__class__ is other.__class__:
    ...             return self.value < other.value
    ...         return NotImplemented
    ...
    >>> class Grade(OrderedEnum):
    ...     A = 5
    ...     B = 4
    ...     C = 3
    ...     D = 2
    ...     F = 1
    ...
    >>> Grade.C < Grade.A
    True

### DuplicateFreeEnum

Levanta un error si se encuentra un nombre de miembro duplicado en lugar de crear un alias:

    >>> class DuplicateFreeEnum(Enum):
    ...     def __init__(self, *args):
    ...         cls = self.__class__
    ...         if any(self.value == e.value for e in cls):
    ...             a = self.name
    ...             e = cls(self.value).name
    ...             raise ValueError(
    ...                 "aliases not allowed in DuplicateFreeEnum:  %r --> %r"
    ...                 % (a, e))
    ...
    >>> class Color(DuplicateFreeEnum):
    ...     RED = 1
    ...     GREEN = 2
    ...     BLUE = 3
    ...     GRENE = 2
    ...
    Traceback (most recent call last):
    ...
    ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'

Nota

Este es un ejemplo útil para subclasificar Enum para agregar o cambiar otros comportamientos, así como no permitir alias. Si el único cambio deseado es no permitir alias, el decorador `unique()` puede usarse en su lugar.

### Planeta

Si `__new__()` o `__init__()` se definen el valor del miembro enum se pasará a estos métodos:

    >>> class Planet(Enum):
    ...     MERCURY = (3.303e+23, 2.4397e6)
    ...     VENUS   = (4.869e+24, 6.0518e6)
    ...     EARTH   = (5.976e+24, 6.37814e6)
    ...     MARS    = (6.421e+23, 3.3972e6)
    ...     JUPITER = (1.9e+27,   7.1492e7)
    ...     SATURN  = (5.688e+26, 6.0268e7)
    ...     URANUS  = (8.686e+25, 2.5559e7)
    ...     NEPTUNE = (1.024e+26, 2.4746e7)
    ...     def __init__(self, mass, radius):
    ...         self.mass = mass       # in kilograms
    ...         self.radius = radius   # in meters
    ...     @property
    ...     def surface_gravity(self):
    ...         # universal gravitational constant  (m3 kg-1 s-2)
    ...         G = 6.67300E-11
    ...         return G * self.mass / (self.radius * self.radius)
    ...
    >>> Planet.EARTH.value
    (5.976e+24, 6378140.0)
    >>> Planet.EARTH.surface_gravity
    9.802652743337129

### Periodo de tiempo

Un ejemplo para mostrar el atributo `ignore` en uso:

    >>> from datetime import timedelta
    >>> class Period(timedelta, Enum):
    ...     "different lengths of time"
    ...     _ignore_ = 'Period i'
    ...     Period = vars()
    ...     for i in range(367):
    ...         Period['day_%d' % i] = i
    ...
    >>> list(Period)[:2]
    [<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]
    >>> list(Period)[-2:]
    [<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]

## ¿Cómo son diferentes las Enums?

Los Enums tienen una metaclase personalizada que afecta muchos aspectos, tanto de las clases derivadas Enum como de sus instancias (miembros).

### Clases Enum

La meta clase `EnumMeta` es responsable de proveer los métodos `__contains__()`, `__dir__()`, `__iter__()` y cualquier otro que permita hacer cosas con una clase `Enum` que falla en una clase típica, como list(Color) o some_enum_var in Color. `EnumMeta` es responsable de asegurar que los otro varios métodos en la clase final `Enum` sean correctos (como `__new__()`, `__getnewargs__()`, `__str__()` y `__repr__()`).

### Miembros de Enum (también conocidos como instancias)

Lo más interesante de los miembros de Enum es que son únicos. `Enum` los crea todos mientras está creando la clase `Enum` misma, y después un `__new__()` personalizado para garantizar que nunca se creen instancias nuevas retornando solo las instancias de miembros existentes.

### Puntos más finos

#### Nombres soportados `__dunder__`

`__members__` es una asignación ordenada de solo lectura de artículos `member_name`:`member`. Solo está disponible en la clase.

`__new__()`, si se especifica, debe crear y retornar los miembros de enumeración; también es una muy buena idea establecer el `_value_` del miembro apropiadamente. Una vez que se crean todos los miembros, ya no se usa.

#### Nombres `_sunder_` compatibles

- `_name_`— nombre del miembro

- `_value_` — valor del miembr0; se puede definir / modificar en `__new__`

- `_missing_` — una función de búsqueda utilizada cuando no se encuentra un valor; puede ser anulado

- `_ignore_` — una lista de nombres, ya sea como una `list()` o una `str()` que no será transformada en miembros, y que se eliminará de la clase final

- `_order_` — usado en código Python 2/3 para asegurar que el orden de los miembros sea consistente (atributo de clase, eliminado durante la creación de la clase)

- `_generate_next_value_` — usado por la Funcional API y por `auto` para obtener un valor apropiado para un miembro enum; puede ser anulado

Nuevo en la versión 3.6: `_missing_`, `_order_`, `_generate_next_value_`

Nuevo en la versión 3.7: `_ignore_`

Para ayudar a mantener sincronizado el código Python 2 / Python 3 se puede proporcionar un atributo `_order_`. Se verificará con el orden real de la enumeración y generará un error si los dos no coinciden:

    >>> class Color(Enum):
    ...     _order_ = 'RED GREEN BLUE'
    ...     RED = 1
    ...     BLUE = 3
    ...     GREEN = 2
    ...
    Traceback (most recent call last):
    ...
    TypeError: member order does not match _order_

Nota

En código Python 2 el atributo `_order_` es necesario ya que el orden de definición se pierde antes de que se pueda registrar.

#### Tipo de miembro `Enum`

Los miembros `Enum` son instancias de su clase `Enum`, y normalmente se accede a ellos como `EnumClass.member`. Bajo ciertas circunstancias también se puede acceder como `EnumClass.member.member`, pero nunca se debe hacer esto ya que esa búsqueda puede fallar, o peor aún, retornar algo además del miembro `Enum` que está buscando (esta es otra buena razón para usar solo mayúsculas en los nombres para los miembros):

    >>> class FieldTypes(Enum):
    ...     name = 0
    ...     value = 1
    ...     size = 2
    ...
    >>> FieldTypes.value.size
    <FieldTypes.size: 2>
    >>> FieldTypes.size.value
    2

Distinto en la versión 3.5.

#### Valor booleano de las clases y miembros `Enum`

Lo miembros `Enum` que están mezclados con tipos sin-`Enum` (como `int`, `str`, etc.) se evalúan de acuerdo con las reglas de tipo mixto; de lo contrario, todos los miembros evalúan como `True`. Para hacer que tu propia evaluación booleana de Enum dependa del valor del miembro, agregue lo siguiente a su clase:

    def __bool__(self):
        return bool(self.value)

las clases `Enum` siempre evalúan como `True`.

#### `Enum` clases con métodos

Si le da a su subclase `Enum` métodos adicionales, como la clase Planet anterior, esos métodos aparecerán en una `dir()` del miembro, pero no de la clase

    >>> dir(Planet)
    ['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__members__', '__module__']
    >>> dir(Planet.EARTH)
    ['__class__', '__doc__', '__module__', 'name', 'surface_gravity', 'value']

#### Combinando miembros de``Flag``

Si no se nombra una combinación de miembros de Flag, el `repr()` incluirá todos los flags con nombre y todas las combinaciones de flags con nombre que estén en el valor

    >>> class Color(Flag):
    ...     RED = auto()
    ...     GREEN = auto()
    ...     BLUE = auto()
    ...     MAGENTA = RED | BLUE
    ...     YELLOW = RED | GREEN
    ...     CYAN = GREEN | BLUE
    ...
    >>> Color(3)  # named combination
    <Color.YELLOW: 3>
    >>> Color(7)      # not named combination
    <Color.CYAN|MAGENTA|BLUE|YELLOW|GREEN|RED: 7>