Soy principalmente un desarrollador de C #, pero actualmente estoy trabajando en un proyecto en Python.
¿Cómo puedo representar el equivalente de una enumeración en Python?
fuente
Soy principalmente un desarrollador de C #, pero actualmente estoy trabajando en un proyecto en Python.
¿Cómo puedo representar el equivalente de una enumeración en Python?
Se han agregado enumeraciones a Python 3.4 como se describe en PEP 435 . También se ha respaldado a 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 y 2.4 en pypi.
Para técnicas de Enum más avanzadas, pruebe la biblioteca aenum (2.7, 3.3+, mismo autor que enum34
. El código no es perfectamente compatible entre py2 y py3, por ejemplo, necesitará __order__
en python 2 ).
enum34
, hacer$ pip install enum34
aenum
, hacer$ 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 lograr 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 puede 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 se usa así:
>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1
El soporte para convertir los valores de nuevo a nombres se puede agregar 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á KeyError si la asignación inversa no existe. Con el primer ejemplo:
>>> Numbers.reverse_mapping['three']
'THREE'
**named
) en la función enum para versiones anteriores es admitir valores personalizados:enum("blue", "red", "green", black=0)
Antes de PEP 435, Python no tenía un equivalente, pero podía implementar el suyo.
A mí mismo, me gusta mantenerlo simple (he visto algunos ejemplos horriblemente complejos en la red), algo así ...
En Python 3.4 ( PEP 435 ), puede hacer que Enum sea la clase base. Esto le brinda un poco de funcionalidad adicional, descrita en el PEP. Por ejemplo, los miembros de enumeración son distintos de los enteros, y están compuestos por a
name
y avalue
.Si no desea escribir los valores, use el siguiente acceso directo:
Enum
Las implementaciones se pueden convertir a 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:fuente
object()
.Aquí hay una implementación:
Aquí está su uso:
fuente
__setattr__(self, name, value)
y tal vez__delattr__(self, name)
para que si escribe accidentalmenteAnimals.DOG = CAT
, no tenga éxito en silencio.Animals.DOG
; Además, los valores de las constantes son cadenas, de modo que las comparaciones con estas constantes son más lentas que si, por ejemplo, se permitieran enteros como valores.setattr()
función dentro del__init__()
método en lugar del__getattr__()
método overidding . Supongo que se supone que esto funciona de la misma manera: class Enum (object): def __init __ (self, enum_string_list): if type (enum_string_list) == list: for enum_string in enum_string_list: setattr (self, enum_string, enum_string) else: raise AttributeErrortry-except
bloque?Si necesita los valores numéricos, esta es la forma más rápida:
En Python 3.x también puede agregar un marcador de posición con estrella al final, que absorberá todos los valores restantes del rango en caso de que no le importe desperdiciar memoria y no pueda contar:
fuente
La mejor solución para usted dependería de lo que requiera de su falsificación
enum
.Enumeración simple:
Si necesita
enum
solo una lista de nombres que identifican diferentes elementos , la solución de Mark Harrison (arriba) es excelente:El uso de a
range
también le permite establecer cualquier valor inicial :Además de lo anterior, si también requiere que los elementos pertenezcan a un contenedor de algún tipo, incrústelos en una clase:
Para usar el elemento enum, ahora necesitaría usar el nombre del contenedor y el nombre del elemento:
Enumeración compleja:
Para largas listas de enumeración o usos más complicados de enumeración, estas soluciones no serán suficientes. Puede consultar la receta de Will Ware para Simular enumeraciones en Python publicada en Python Cookbook . Una versión en línea de eso está disponible aquí .
Más información:
PEP 354: Enumeraciones en Python tiene los detalles interesantes de una propuesta de enumeración en Python y por qué fue rechazada.
fuente
range
usted puede omitir el primer argumento si es 0my_enum = dict(map(reversed, enumerate(str.split('Item0 Item1 Item2'))))
. Entoncesmy_enum
puede usarse en la búsqueda, por ejemplo,my_enum['Item0']
puede ser un índice en una secuencia. Es posible que desee ajustar el resultado destr.split
una función que arroje una excepción si hay duplicados.Flag1, Flag2, Flag3 = [2**i for i in range(3)]
El patrón de enumeración typesafe que se utilizó en Java pre-JDK 5 tiene varias ventajas. Al igual que en la respuesta de Alexandru, crea una clase y los campos de nivel de clase son los valores de enumeración; sin embargo, los valores de enumeración son instancias de la clase en lugar de enteros pequeños. Esto tiene la ventaja de que sus valores de enumeración no se comparan inadvertidamente iguales a enteros pequeños, puede controlar cómo se imprimen, agregar métodos arbitrarios si eso es útil y hacer afirmaciones usando isinstance:
Un hilo reciente en python-dev señaló que hay un par de bibliotecas de enumeraciones en la naturaleza, que incluyen:
fuente
Una clase de Enum puede ser de una sola línea.
Cómo usarlo (búsqueda directa e inversa, claves, valores, elementos, etc.)
fuente
in
palabra clave para buscar miembros que sea ordenada. Ejemplo de uso:'Claimed' in Enum(['Unclaimed', 'Claimed'])
Entonces, estoy de acuerdo. No apliquemos la seguridad de tipos en Python, pero me gustaría protegerme de errores tontos. Entonces, ¿qué pensamos sobre esto?
Me evita la colisión de valores al definir mis enumeraciones.
Hay otra ventaja útil: búsquedas inversas realmente rápidas:
fuente
Animal = Enum('horse', 'dog', 'cat')
. También capturo el ValueError en getattr en el caso de que falte un elemento en self.values; en su lugar, parece mejor generar un AttributeError con la cadena de nombre suministrada. No pude lograr que la metaclase funcionara en Python 2.7 debido a mi conocimiento limitado en esa área, pero mi clase personalizada Enum funciona bien con métodos de instancia directa.Python no tiene un equivalente incorporado
enum
, y otras respuestas tienen ideas para implementar la suya (también puede estar interesado en la versión superior en el libro de cocina de Python).Sin embargo, en situaciones en las
enum
que se requeriría una en C, generalmente termino usando cadenas simples : debido a la forma en que se implementan los objetos / atributos, (C) Python está optimizado para funcionar muy rápido con cadenas cortas de todos modos, por lo que no habría Realmente no hay ningún beneficio de rendimiento al usar enteros. Para evitar errores tipográficos / valores no válidos, puede insertar cheques en lugares seleccionados.(Una desventaja en comparación con el uso de una clase es que pierde el beneficio de autocompletar)
fuente
El 10/05/2013, Guido acordó aceptar PEP 435 en la biblioteca estándar Python 3.4. ¡Esto significa que Python finalmente tiene soporte incorporado para enumeraciones!
Hay un backport disponible para Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 y 2.4. Está en Pypi como enum34 .
Declaración:
Representación:
Iteración:
Acceso programático:
Para más información, consulte la propuesta . La documentación oficial probablemente seguirá pronto.
fuente
Prefiero definir enumeraciones en Python así:
Es más a prueba de errores que usar números enteros, ya que no tiene que preocuparse por asegurarse de que los números enteros sean únicos (por ejemplo, si dijera Perro = 1 y Gato = 1, estaría jodido).
Es más a prueba de errores que usar cadenas, ya que no tiene que preocuparse por los errores tipográficos (por ejemplo, x == "catt" falla en silencio, pero x == Animal.Catt es una excepción en tiempo de ejecución).
fuente
Úselo así:
Si solo desea símbolos únicos y no le importan los valores, reemplace esta línea:
con este:
fuente
enum(names)
aenum(*names)
, entonces podrías dejar el paréntesis extra cuando lo llames.Desde Python 3.4 habrá soporte oficial para las enumeraciones. Puede encontrar documentación y ejemplos aquí en la página de documentación de Python 3.4 .
fuente
Hmmm ... supongo que lo más parecido a una enumeración sería un diccionario, definido así:
o
Luego, puede usar el nombre simbólico para las constantes como esta:
Hay otras opciones, como una lista de tuplas o una tupla de tuplas, pero el diccionario es el único que le proporciona una forma "simbólica" (cadena constante) para acceder al valor.
Editar: ¡Me gusta la respuesta de Alexandru también!
fuente
Otra implementación muy simple de una enumeración en Python, usando
namedtuple
:o alternativamente,
Al igual que el método anterior que las subclases
set
, esto permite:Pero tiene más flexibilidad, ya que puede tener diferentes claves y valores. Esto permite
para actuar como se espera si usa la versión que completa los valores de números secuenciales.
fuente
Lo que uso:
Cómo utilizar:
Entonces, esto le da constantes enteras como state.PUBLISHED y las dos tuplas para usar como opciones en los modelos de Django.
fuente
davidg recomienda usar dictados. Iría un paso más allá y usaría conjuntos:
Ahora puede probar si un valor coincide con uno de los valores del conjunto de la siguiente manera:
Sin embargo, como dF, generalmente solo uso constantes de cadena en lugar de enumeraciones.
fuente
Mantenlo simple:
Entonces:
fuente
Este es el mejor que he visto: "Enums de primera clase en Python"
http://code.activestate.com/recipes/413486/
Te da una clase, y la clase contiene todas las enumeraciones. Las enumeraciones se pueden comparar entre sí, pero no tienen ningún valor en particular; no puedes usarlos como un valor entero. (Al principio me resistí a esto porque estoy acostumbrado a las enumeraciones en C, que son valores enteros. Pero si no puede usarlo como un entero, no puede usarlo como un entero por error, así que en general creo que es una victoria .) Cada enumeración es un valor único. Puede imprimir enumeraciones, puede iterar sobre ellas, puede probar que un valor de enumeración está "en" la enumeración. Es bastante completo y resbaladizo.
Editar (cfi): el enlace anterior no es compatible con Python 3. Aquí está mi puerto de enum.py a Python 3:
fuente
.__int__()
método debería generar una excepción para una enumeración; pero debería haber una manera de obtener el valor. Y debería ser posible establecer valores enteros específicos en el momento de la definición de clase, por lo que podría usar una enumeración para cosas como las constantes en elstat
módulo.He tenido la ocasión de necesitar una clase Enum, con el propósito de decodificar un formato de archivo binario. Las características que deseaba eran una definición concisa de enumeración, la capacidad de crear libremente instancias de enumeración mediante un valor entero o una cadena, y una presentación útil
repr
. Esto es lo que terminé con:Un ejemplo caprichoso de usarlo:
Características clave:
str()
,int()
yrepr()
todos producen la salida más útil posible, respectivamente, el nombre de la enumeración, su valor entero y una expresión de Python que se evalúa de nuevo en la enumeración.is
fuente
__instancecheck__
método. Las clases no son colecciones de instancias, por lo que1 in Fruit
es absurdo. Sin embargo, la versión vinculada admiteisinstance(1, Fruit)
cuál sería más correcto en términos de la noción de clases e instancias.El nuevo estándar en Python es PEP 435 , por lo que una clase Enum estará disponible en futuras versiones de Python:
Sin embargo, para comenzar a usarlo ahora, puede instalar la biblioteca original que motivó el PEP:
Luego puede usarlo según su guía en línea :
fuente
Si lo nombra, es su problema, pero si no crea objetos en lugar de valores le permite hacer esto:
Cuando use otras implementaciones ubicadas aquí (también cuando use instancias con nombre en mi ejemplo) debe estar seguro de que nunca intenta comparar objetos de diferentes enumeraciones. Porque aquí hay una posible trampa:
¡Ay!
fuente
Realmente me gusta la solución de Alec Thomas (http://stackoverflow.com/a/1695250):
Es elegante y de aspecto limpio, pero es solo una función que crea una clase con los atributos especificados.
Con una pequeña modificación a la función, podemos hacer que actúe un poco más 'enumy':
Esto crea una enumeración basada en un tipo especificado. Además de dar acceso a los atributos como la función anterior, se comporta como cabría esperar de una Enum con respecto a los tipos. También hereda la clase base.
Por ejemplo, enumeraciones enteras:
Otra cosa interesante que se puede hacer con este método es personalizar el comportamiento específico anulando los métodos integrados:
fuente
El paquete enum de PyPI proporciona una implementación robusta de enums. Una respuesta anterior mencionó PEP 354; esto fue rechazado pero la propuesta se implementó http://pypi.python.org/pypi/enum .
El uso es fácil y elegante:
fuente
La sugerencia de Alexandru de usar constantes de clase para enumeraciones funciona bastante bien.
También me gusta agregar un diccionario para cada conjunto de constantes para buscar una representación de cadena legible para humanos.
Esto sirve para dos propósitos: a) proporciona una forma simple de imprimir su enumeración yb) el diccionario agrupa lógicamente las constantes para que pueda probar la membresía.
fuente
Aquí hay un enfoque con algunas características diferentes que considero valiosas:
¡y lo más importante, evita las comparaciones entre enumeraciones de diferentes tipos !
Basado de cerca en http://code.activestate.com/recipes/413486-first-class-enums-in-python .
Muchos documentos incluidos aquí para ilustrar las diferencias de este enfoque.
fuente
Aquí hay una variante de la solución de Alec Thomas :
fuente
Esta solución es una forma simple de obtener una clase para la enumeración definida como una lista (no más asignaciones enteras molestas):
enumeration.py:
ejemplo.py:
fuente
type(class_name, (object,), dict(...))
en su lugar?Si bien la propuesta de enumeración original, PEP 354 , fue rechazada hace años, sigue volviendo a aparecer. Se pretendía agregar algún tipo de enumeración a 3.2, pero se retrasó a 3.3 y luego se olvidó. Y ahora hay un PEP 435 destinado a ser incluido en Python 3.4. La implementación de referencia de PEP 435 es
flufl.enum
.A partir de abril de 2013, parece haber un consenso general de que se debe agregar algo a la biblioteca estándar en 3.4, siempre y cuando las personas puedan ponerse de acuerdo sobre lo que ese "algo" debería ser. Esa es la parte difícil. Vea los hilos que comienzan aquí y aquí , y media docena de otros hilos en los primeros meses de 2013.
Mientras tanto, cada vez que surge esto, aparece una gran cantidad de nuevos diseños e implementaciones en PyPI, ActiveState, etc., por lo que si no le gusta el diseño FLUFL, intente una búsqueda de PyPI .
fuente
Usa lo siguiente.
Lo usé para las opciones de modelo de Django , y se ve muy pitónico. No es realmente una enumeración, pero hace el trabajo.
fuente