Вы можете отслеживать значения внутри, но это немного хлопотно:
попытка 1
_values = [k for k in vars().keys() if not k.startswith('_')]
проблемы 1
>>> # _values is a member
>>> Color._values
<Color._huh: ['RED', 'BLUE', 'GREEN']>
попытка 2
Используйте Constant
из этот ответ
_values = Constant([k for k in vars().keys() if not k.startswith('_')])
проблемы 2
Это не совсем константа, поскольку вы все еще можете добавить к списку - но это можно решить, приведя к tuple
:
_values = Constant(tuple([k for k in vars().keys() if not k.startswith('_')]))
Однако это все еще не решает проблему UNKNOWN
.
Решение
Используя Python 3.6 или aenum 2.0
1 , вы можете указать метод _missing_
, который будет вызываться, чтобы дать вашему классу последний шанс перед повышением ValueError
:
class Constant: # use Constant(object) if in Python 2
def __init__(self, value):
self.value = value
def __get__(self, *args):
return self.value
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.value)
class Color(Enum):
RED = 'red'
BLUE = 'blue'
GREEN = 'green'
UNKNOWN = 'unknown'
_values = Constant(tuple([k for k in vars().keys() if not k.startswith('_')]))
@classmethod
def _missing_(cls, name):
if name.lower() in cls._values:
return cls(name.lower())
else:
return cls.UNKNOWN
или
class Color(Enum):
RED = 'red'
BLUE = 'blue'
GREEN = 'green'
UNKNOWN = 'unknown'
@classmethod
def _missing_(cls, name):
if name == name.lower():
# avoid infinite recursion
return cls.UNKNOWN
else:
return cls(name.lower())
N.B. : _missing_
должен быть возвращен только элемент enum или None
- более поздние версии Python будут выдавать TypeError
, если что-либо еще будет возвращено.
1 Раскрытие информации: я являюсь автором Python stdlib Enum
, enum34
backport и Advanced Enumeration ( aenum
) библиотека.