Aggiornamento: 2017-03-01
In Python 3.6 (e Aenum 2.0
) Flag
e IntFlag
sono stati aggiunti classi; parte di quella era una nuova auto()
helper che rende questo banalmente semplice:
>>> 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'>]
risposta originale
La difficoltà con una classe AutoStr
è che il nome del membro enum non è passato nel codice che lo crea, quindi non è disponibile per l'uso. Un'altra ruga è che str
è immutabile, quindi non possiamo cambiare quei tipi di enumerazione dopo che sono stati creati (ad esempio usando un class decorator).
La cosa più semplice da fare è usare il Functional API:
Animal = Enum('Animal', [(a, a) for a in ('horse', 'dog')], type=str)
che ci dà:
>>> list(Animal)
[<Animal.horse: 'horse'>, <Animal.dog: 'dog'>]
>>> Animal.dog == 'dog'
True
La prossima cosa più facile da fare, supponendo che si vuole fare una classe di base per il tuo uso futuro di enumerazione, sarebbe qualcosa di simile al mio DocEnem
:
class DocEnum(Enum):
"""
compares equal to all cased versions of its name
accepts a doctring for each member
"""
def __new__(cls, *args):
"""Ignores arguments (will be handled in __init__)"""
obj = object.__new__(cls)
obj._value_ = None
return obj
def __init__(self, doc=None):
# first, fix _value_
self._value_ = self._name_.lower()
self.__doc__ = doc
def __eq__(self, other):
if isinstance(other, basestring):
return self._value_ == other.lower()
elif not isinstance(other, self.__class__):
return NotImplemented
return self is other
def __ne__(self, other):
return not self == other
e in uso:
class SpecKind(DocEnum):
REQUIRED = "required value"
OPTION = "single value per name"
MULTI = "multiple values per name (list form)"
FLAG = "boolean value per name"
KEYWORD = 'unknown options'
Nota che a differenza della prima opzione, DocEnum
membri sono nonstr
s.
Se si vuole farlo nel modo più duro: sottoclasse EnumMeta
e violino con i nuovi Enum
s' Dizionario classe vengono creati prima i membri:
from enum import EnumMeta, Enum, _EnumDict
class StrEnumMeta(EnumMeta):
def __new__(metacls, cls, bases, oldclassdict):
"""
Scan through `oldclassdict` and convert any value that is a plain tuple
into a `str` of the name instead
"""
newclassdict = _EnumDict()
for k, v in oldclassdict.items():
if v ==():
v = k
newclassdict[k] = v
return super().__new__(metacls, cls, bases, newclassdict)
class AutoStrEnum(str, Enum, metaclass=StrEnumMeta):
"base class for name=value str enums"
class Animal(AutoStrEnum):
horse =()
dog =()
whale =()
print(Animal.horse)
print(Animal.horse == 'horse')
print(Animal.horse.name, Animal.horse.value)
Il che ci dà:
Animal.horse
True
horse horse
Disclosure: Sono l'autore dello Python stdlib Enum
, dello enum34
backport e della libreria Advanced Enumeration (aenum
).
intendi 'Animal.dog.value == 'dog''? –
correlati: http://www.acooke.org/cute/Pythonssad0.html – wim
Penso che potrebbe essere fatto modificando EnumMeta._create_() in enum.py (https://hg.python.org/cpython/file /3.4/Lib/enum.py#l295, tuttavia non può essere immediatamente cancellato a causa di ValueError sui nomi sundered provenienti da _is_sunder() per proteggere il codice. Tuttavia, se names = ['red', 'green', 'blue' ] e Color = Enum ('Colore', names = zip (nomi, nomi)), quindi Color.red.value == 'red', Color.green.value == 'green' e Color.blue.value == 'blu'. –