"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:

  Caso de miembros de EnumDebido a que las enumeraciones se usan para
  representar constantes, recomendamos usar nombres UPPER_CASE para
  los miembros de enumeración, y usaremos ese estilo en nuestros
  ejemplos.


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 EnumLos 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:

  El objetivo del método predeterminado "_generate_next_value_()" es
  proporcionar el siguiente "int" en secuencia con el último "int"
  proporcionado, pero la forma en que lo hace es un detalle de
  implementación y puede cambiar.

Nota:

  El método "_generate_next_value_()" debe definirse antes que
  cualquier miembro.


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__()" o "__init__()", los valores
que se hayan dado al miembro enum se pasarán a esos métodos. Ver
Planet 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, por ejemplo, "int" de arriba. Esta
   restricción no se aplica a las mezclas que solo agregan métodos y
   no especifican otro tipo.

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. Cadenas de caracteres literales formateadas, "str.format()", y
   "format()" usará el tipo mixto "__format__()" a menos que
   "__str__()" o "__format__()" se sobreescriba en la subclase, en
   cuyo caso se utilizarán los métodos anulados o "Enum". Use los
   códigos de formato !s y !r para forzar el uso de los métodos "Enum"
   de las clases "__str__()" y "__repr__()".


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

Para hacer un "AutoNumber" de propósito más general, agregue "*args" a
la firma:

   >>> 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
   ...

Luego, cuando hereda de "AutoNumber", puede escribir su propio
"__init__" para manejar cualquier argumento adicional:

   >>> 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 miembro; 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.


_Private__names
~~~~~~~~~~~~~~~

Private names will be normal attributes in Python 3.11 instead of
either an error or a member (depending on if the name ends with an
underscore). Using these names in 3.9 and 3.10 will issue a
"DeprecationWarning".


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

Nota:

  This behavior is deprecated and will be removed in 3.11.

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>

Nota:

  In 3.11 unnamed combinations of flags will only produce the
  canonical flag members (aka single-value flags).  So "Color(7)"
  would produce something like "<Color.BLUE|GREEN|RED: 7>".
