not - ¿Cómo debo emular y/o evitar enum en Python?
python enumerate (6)
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, casi siempre son 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
Entonces, en un cliente de esta clase.
dtn = DoTheNeeful( DoTheNeeful.ONE_CHOICE )
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ódigo de 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)
La forma integrada de hacer enumeraciones es:
(FOO, BAR, BAZ) = range(3)
que funciona bien para juegos pequeños, pero tiene algunos inconvenientes:
- necesitas contar la cantidad de elementos a mano
- no puedes saltear valores
- si agrega un nombre, también necesita actualizar el número de rango
Para una implementación enum completa en python, ver: http://code.activestate.com/recipes/67107/
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 is
lugar de ==
está tomando un riesgo aquí: asume que las personas están usando your_module.FOO_BAR
lugar de la cadena ''FOO_BAR''
(que normalmente será internado de manera que coincida, pero eso ciertamente puede '' No se puede contar), por lo que puede no ser apropiado según el contexto.
Una de las ventajas de hacerlo de esta manera es que al buscar en cualquier lugar donde se almacena una referencia a esa cadena, es obvio de dónde proviene; FOO_BAZ
es mucho menos ambiguo que 2
.
Además de eso, la otra cosa que ofende mis sensibilidades Pythonic es que la clase que propones es el uso de split()
. ¿Por qué no simplemente pasar una tupla, lista u otro enumerable para empezar?
Los enum han sido propuestos para su inclusión en el lenguaje anteriormente, pero fueron rechazados (ver http://www.python.org/dev/peps/pep-0354/ ), aunque existen paquetes existentes que podrías usar en lugar de escribir tu propia implementación. :
- enum: http://pypi.python.org/pypi/enum
- SymbolType (no es lo mismo que enums, pero sigue siendo útil): http://pypi.python.org/pypi/SymbolType
- O simplemente haz una búsqueda
Empecé con algo que se parece mucho a la respuesta de S.Lott, pero solo sobrecargué ''str'' y ''eq'' (en lugar de toda la clase de objeto) para poder 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
Imprimir (x) arrojará el nombre en lugar del valor y dos valores que contengan Spring serán iguales entre sí.
>>> x = enumSeason(enumSeason.Spring)
>>> print(x)
Spring
>>> y = enumSeason(enumSeason.Spring)
>>> x == y
True
Hay mucha buena discusión aquí .