2008-09-20 15 views
6

He estado usando una clase pequeña para emular Enums en algunos proyectos de Python. ¿Hay una mejor manera o esto tiene más sentido para algunas situaciones?¿Cómo debo emular y/o evitar enum en Python?

código

Clase aquí:

class Enum(object): 
'''Simple Enum Class 
Example Usage: 
>>> codes = Enum('FOO BAR BAZ') # codes.BAZ will be 2 and so on ...''' 
def __init__(self, names): 
    for number, name in enumerate(names.split()): 
     setattr(self, name, number) 
+3

duplicados de http://stackoverflow.com/questions/36932/whats-the-best-way-to-implement-an-enum-in-python –

+0

acuerdo. Lo siento, debería haberlo encontrado antes. – Lanny

Respuesta

3

Hay mucha discusión buena here.

2

La forma incorporado hacer enumeraciones es:

(FOO, BAR, BAZ) = range(3) 

que funciona bien para conjuntos pequeños, pero tiene algunos inconvenientes:

  • que necesita para contar el número de elementos a mano
  • no puede omitir los valores
  • si agrega o Nombre ne, también es necesario actualizar el número de gama

Para una implementación de enumeración completa de pitón, vea: http://code.activestate.com/recipes/67107/

+1

notablemente, Python generará una excepción si el tamaño del rango no coincide con el recuento de elementos. – cmcginty

3

Lo que veo más a menudo es esto, en el contexto del módulo de nivel superior:

FOO_BAR = 'FOO_BAR' 
FOO_BAZ = 'FOO_BAZ' 
FOO_QUX = 'FOO_QUX' 

... y después ...

if something is FOO_BAR: pass # do something here 
elif something is FOO_BAZ: pass # do something else 
elif something is FOO_QUX: pass # do something else 
else: raise Exception('Invalid value for something') 

Tenga en cuenta que el uso de la is en lugar de == está tomando un riesgo aquí - se supone que la gente está usando your_module.FOO_BAR en lugar de la cadena 'FOO_BAR' (que normalmente se intercalará de manera que is coincidirá, pero que ciertamente no se puede contar), y por lo tanto puede no ser apropiado dependiendo del contexto.

Una de las ventajas de hacerlo de esta manera es que al buscar en cualquier parte una referencia a esa cadena que se está almacenando, es inmediatamente obvio de dónde vino; FOO_BAZ es mucho menos ambiguo que 2.

Además de eso, la otra cosa que ofende a mi sensibilidad Pythonic es que la clase que propone es el uso de split(). ¿Por qué no simplemente pasar una tupla, lista u otro enumerable para empezar?

4

El caso de enumeración más común es valores enumerados que forman parte de un patrón de diseño de estado o estrategia. Las enumeraciones son estados específicos o estrategias opcionales específicas para ser utilizadas.En este caso, son casi siempre parte de una definición de clase

class DoTheNeedful(object): 
    ONE_CHOICE = 1 
    ANOTHER_CHOICE = 2 
    YET_ANOTHER = 99 
    def __init__(self, aSelection): 
     assert aSelection in (self.ONE_CHOICE, self.ANOTHER_CHOICE, self.YET_ANOTHER) 
     self.selection= aSelection 

Luego, en un cliente de esta clase.

dtn = DoTheNeeful(DoTheNeeful.ONE_CHOICE) 
1

Empecé con algo que se parece mucho a la respuesta de S. Lott pero sólo sobrecargado 'str' y 'eq' (en lugar de toda la clase de objeto) para que yo pudiera imprimir y comparar el valor de la enumeración.

class enumSeason(): 
    Spring = 0 
    Summer = 1 
    Fall = 2 
    Winter = 3 
    def __init__(self, Type): 
     self.value = Type 
    def __str__(self): 
     if self.value == enumSeason.Spring: 
      return 'Spring' 
     if self.value == enumSeason.Summer: 
      return 'Summer' 
     if self.value == enumSeason.Fall: 
      return 'Fall' 
     if self.value == enumSeason.Winter: 
      return 'Winter' 
    def __eq__(self,y): 
     return self.value==y.value 

de impresión (x) dará el nombre en lugar del valor y dos valores de sujeción de muelle será igual a uno del otro.

>>> x = enumSeason(enumSeason.Spring) 
    >>> print(x) 
    Spring 
    >>> y = enumSeason(enumSeason.Spring) 
    >>> x == y 
    True