enum
— Поддержка перечислений¶
Добавлено в версии 3.4.
Исходный код: Lib/enum.py
Перечисление:
представляет собой набор символьных имен (элементов), привязанных к уникальным значениям
может быть повторен для возврата его канонических (т.е. не являющихся псевдонимами) элементов в порядке определения
использует синтаксис call для возврата элементов по значению
использует синтаксис index для возврата элементов по имени
Перечисления создаются либо с помощью синтаксиса class
, либо с помощью синтаксиса вызова функции:
>>> from enum import Enum
>>> # class syntax
>>> class Color(Enum):
... RED = 1
... GREEN = 2
... BLUE = 3
>>> # functional syntax
>>> Color = Enum('Color', ['RED', 'GREEN', 'BLUE'])
Несмотря на то, что мы можем использовать синтаксис class
для создания перечислений, перечисления не являются обычными классами Python. Более подробную информацию смотрите в How are Enums different?.
Примечание
Номенклатура
Класс
Color
является перечислением (или enum)Атрибуты
Color.RED
,Color.GREEN
, и т.д. являются элементами перечисления (или members) и функционально являются константами.Элементы перечисления имеют имена и значения (имя
Color.RED
равноRED
, значениеColor.BLUE
равно3
и т.д.).
Содержимое модуля¶
type
для перечисления и его подклассов.Базовый класс для создания перечисляемых констант.
Базовый класс для создания перечисляемых констант, которые могут быть объединены с помощью побитовых операций без потери их принадлежности к
Flag
.Перечисление со значениями
CONTINUOUS
,NAMED_FLAGS
, иUNIQUE
для использования сverify()
, чтобы убедиться, что данное перечисление удовлетворяет различным ограничениям.Перечисление со значениями
STRICT
,CONFORM
,EJECT
, иKEEP
, которое позволяет более точно контролировать, как обрабатываются недопустимые значения в перечислении.Экземпляры заменяются соответствующим значением для элементов перечисления.
StrEnum
по умолчанию используется строчная версия имени элемента, в то время как другие перечисления по умолчанию имеют значение 1 и увеличиваются с этого значения.Позволяет элементам
Enum
иметь атрибуты, не вступающие в конфликт с именами элементов.Декоратор класса Enum, который гарантирует, что к любому значению привязано только одно имя.
Декоратор класса Enum, который проверяет выбираемые пользователем ограничения для перечисления.
Сделайте
obj
элементом. Может использоваться в качестве декоратора.Не добавляйте
obj
в качестве элемента. Может использоваться в качестве декоратора.Возвращает список всех целых чисел в степени двойки, содержащихся во флаге.
Добавлено в версии 3.6: Flag
, IntFlag
, auto
Добавлено в версии 3.11: StrEnum
, EnumCheck
, ReprEnum
, FlagBoundary
, property
, member
, nonmember
, global_enum
, show_flag_values
Типы данных¶
- class enum.EnumType¶
EnumType - это metaclass для enum перечислений. Можно создать подкласс EnumType - подробности смотрите в Subclassing EnumType.
EnumType отвечает за установку правильных методов
__repr__()
,__str__()
,__format__()
, и__reduce__()
для конечного enum, а также за создание элементов enum, правильную обработку дубликатов, обеспечение итерации по классу enum и т.д.- __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)¶
Этот метод вызывается двумя различными способами:
чтобы найти существующего участника:
- cls:
Вызываемый класс enum.
- ценность:
Значение для поиска.
чтобы использовать перечисление
cls
для создания нового перечисления (только если существующее перечисление не содержит элементов):- cls:
Вызываемый класс enum.
- ценность:
Имя нового перечисления, которое нужно создать.
- имена:
Имена/значения элементов для нового перечисления.
- модуль:
Имя модуля, в котором создается новое перечисление.
- квалификационное имя:
Фактическое местоположение в модуле, где можно найти это перечисление.
- тип:
Комбинированный тип для нового перечисления.
- начало:
Первое целое значение для перечисления (используется
auto
).- граница:
Как обрабатывать значения, выходящие за пределы диапазона, в результате битовых операций (только
Flag
).
- __contains__(cls, member)¶
Возвращает
True
, если элемент принадлежит кcls
:>>> some_var = Color.RED >>> some_var in Color True
Примечание
В Python 3.12 можно будет проверять значения элементов, а не только членов; до тех пор, если при проверке содержимого используется элемент, не являющийся перечислимым, будет генерироваться
TypeError
.
- __dir__(cls)¶
Возвращает
['__class__', '__doc__', '__members__', '__module__']
и имена членов в cls:>>> dir(Color) ['BLUE', 'GREEN', 'RED', '__class__', '__contains__', '__doc__', '__getitem__', '__init_subclass__', '__iter__', '__len__', '__members__', '__module__', '__name__', '__qualname__']
- __getattr__(cls, name)¶
Возвращает элемент перечисления в cls, соответствующий name, или выдает
AttributeError
:>>> Color.GREEN <Color.GREEN: 2>
- __getitem__(cls, name)¶
Возвращает элемент перечисления в cls, соответствующий name, или выдает
KeyError
:>>> Color['BLUE'] <Color.BLUE: 3>
- __iter__(cls)¶
Возвращает каждый элемент в cls в порядке определения:
>>> list(Color) [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 3>]
- __len__(cls)¶
Возвращает номер участника в cls:
>>> len(Color) 3
- __reversed__(cls)¶
Возвращает каждый элемент в cls в порядке, обратном определению:
>>> list(reversed(Color)) [<Color.BLUE: 3>, <Color.GREEN: 2>, <Color.RED: 1>]
Добавлено в версии 3.11: До 3.11
enum
использовался типEnumMeta
, который сохранялся как псевдоним.
- class enum.Enum¶
Enum - это базовый класс для всех перечислений enum.
- name¶
Имя, используемое для определения элемента
Enum
:>>> Color.BLUE.name 'BLUE'
- value¶
Значение, присвоенное элементу
Enum
:>>> Color.RED.value 1
Значение элемента может быть задано в виде
__new__()
.Примечание
Значения элементов перечисления
Значения элементов могут быть любыми:
int
,str
, и т.д. Если точное значение не имеет значения, вы можете использоватьauto
экземпляра, и для вас будет выбрано подходящее значение. Более подробную информацию смотрите в разделеauto
.Хотя можно использовать изменяемые/хэшируемые значения, такие как
dict
,list
или изменяемыйdataclass
, они будут оказывать квадратичное влияние на производительность при создании по сравнению с общим количеством изменяемых/не хэшируемых значений в перечислении.
- _name_¶
Имя участника.
- _order_¶
Больше не используется, сохранен для обеспечения обратной совместимости. (атрибут class, удален при создании класса).
- _ignore_¶
_ignore_
используется только во время создания и удаляется из списка после завершения создания._ignore_
- это список имен, которые не станут участниками и чьи имена также будут удалены из завершенного списка. Пример смотрите в TimePeriod.
- __dir__(self)¶
Возвращает
['__class__', '__doc__', '__module__', 'name', 'value']
и любые общедоступные методы, определенные в self.__class__:>>> from datetime import date >>> class Weekday(Enum): ... MONDAY = 1 ... TUESDAY = 2 ... WEDNESDAY = 3 ... THURSDAY = 4 ... FRIDAY = 5 ... SATURDAY = 6 ... SUNDAY = 7 ... @classmethod ... def today(cls): ... print('today is %s' % cls(date.today().isoweekday()).name) >>> dir(Weekday.SATURDAY) ['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'today', 'value']
- _generate_next_value_(name, start, count, last_values)¶
- имя:
Имя определяемого элемента (например, «КРАСНЫЙ»).
- начало:
Начальное значение для перечисления; значение по умолчанию равно 1.
- считать:
Количество участников, определенное в настоящее время, не включает этого участника.
- последние_значения:
Список предыдущих значений.
staticmethod, который используется для определения следующего значения, возвращаемого
auto
:>>> from enum import auto >>> class PowersOfThree(Enum): ... @staticmethod ... def _generate_next_value_(name, start, count, last_values): ... return 3 ** (count + 1) ... FIRST = auto() ... SECOND = auto() >>> PowersOfThree.SECOND.value 9
- __init_subclass__(cls, **kwds)¶
classmethod, который используется для дальнейшей настройки последующих подклассов. По умолчанию ничего не делает.
- _missing_(cls, value)¶
classmethod для поиска значений, не найденных в cls. По умолчанию он ничего не делает, но может быть переопределен для реализации пользовательского режима поиска:
>>> from enum import StrEnum >>> class Build(StrEnum): ... DEBUG = auto() ... OPTIMIZED = auto() ... @classmethod ... def _missing_(cls, value): ... value = value.lower() ... for member in cls: ... if member.value == value: ... return member ... return None >>> Build.DEBUG.value 'debug' >>> Build('deBUG') <Build.DEBUG: 'debug'>
- __repr__(self)¶
Возвращает строку, используемую для вызовов repr(). По умолчанию возвращает имя Enum, имя элемента и значение, но может быть переопределено:
>>> class OtherStyle(Enum): ... ALTERNATE = auto() ... OTHER = auto() ... SOMETHING_ELSE = auto() ... def __repr__(self): ... cls_name = self.__class__.__name__ ... return f'{cls_name}.{self.name}' >>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f"{OtherStyle.ALTERNATE}" (OtherStyle.ALTERNATE, 'OtherStyle.ALTERNATE', 'OtherStyle.ALTERNATE')
- __str__(self)¶
Возвращает строку, используемую для вызовов str(). По умолчанию возвращает имя Enum и имя элемента, но может быть переопределено:
>>> class OtherStyle(Enum): ... ALTERNATE = auto() ... OTHER = auto() ... SOMETHING_ELSE = auto() ... def __str__(self): ... return f'{self.name}' >>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f"{OtherStyle.ALTERNATE}" (<OtherStyle.ALTERNATE: 1>, 'ALTERNATE', 'ALTERNATE')
- __format__(self)¶
Возвращает строку, используемую для вызовов format() и f-string. По умолчанию возвращает
__str__()
возвращаемое значение, но может быть переопределено:>>> class OtherStyle(Enum): ... ALTERNATE = auto() ... OTHER = auto() ... SOMETHING_ELSE = auto() ... def __format__(self, spec): ... return f'{self.name}' >>> OtherStyle.ALTERNATE, str(OtherStyle.ALTERNATE), f"{OtherStyle.ALTERNATE}" (<OtherStyle.ALTERNATE: 1>, 'OtherStyle.ALTERNATE', 'ALTERNATE')
- class enum.IntEnum¶
IntEnum - это то же самое, что и Enum, но его элементы также являются целыми числами и могут использоваться везде, где можно использовать целое число. Если какая-либо целочисленная операция выполняется с элементом IntEnum, результирующее значение теряет свой статус перечисления.
>>> from enum import IntEnum >>> class Number(IntEnum): ... ONE = 1 ... TWO = 2 ... THREE = 3 ... >>> Number.THREE <Number.THREE: 3> >>> Number.ONE + Number.TWO 3 >>> Number.THREE + 5 8 >>> Number.THREE == 3 True
Примечание
Использование
auto
сIntEnum
приводит к получению целых чисел с возрастающим значением, начиная с1
.Изменено в версии 3.11:
__str__()
теперьint.__str__()
для лучшей поддержки варианта использования *замены существующих констант.__format__()
уже былint.__format__()
по той же причине.
- class enum.StrEnum¶
StrEnum - это то же самое, что и Enum, но его элементы также являются строками и могут использоваться практически в тех же местах, что и строка. Результат любой операции со строкой, выполняемой над элементом StrEnum или с его помощью, не является частью перечисления.
Примечание
В stdlib есть места, которые проверяют наличие точного
str
вместоstr
подкласса (т.е.type(unknown) == str
вместоisinstance(unknown, str)
), и в этих местах вам нужно будет использоватьstr(StrEnum.member)
.Примечание
Использование
auto
сStrEnum
приводит к вводу имени элемента в нижнем регистре в качестве значения.Примечание
__str__()
- этоstr.__str__()
для лучшей поддержки варианта использования *замены существующих констант.__format__()
аналогичноstr.__format__()
по той же причине.Добавлено в версии 3.11.
- class enum.Flag¶
Элементы Flag поддерживают побитовые операторы
&
(И),|
(ИЛИ),^
(XOR) и~
(ИНВЕРТИРОВАТЬ); результаты этих операторов являются элементами перечисления.- __contains__(self, value)¶
Возвращает True, если значение находится в self:
>>> from enum import Flag, auto >>> class Color(Flag): ... RED = auto() ... GREEN = auto() ... BLUE = auto() >>> purple = Color.RED | Color.BLUE >>> white = Color.RED | Color.GREEN | Color.BLUE >>> Color.GREEN in purple False >>> Color.GREEN in white True >>> purple in white True >>> white in purple False
- __iter__(self):
Возвращает все содержащиеся в нем элементы, не являющиеся псевдонимами:
>>> list(Color.RED) [<Color.RED: 1>] >>> list(purple) [<Color.RED: 1>, <Color.BLUE: 4>]
Добавлено в версии 3.11.
- __len__(self):
Возвращает количество участников во флаге:
>>> len(Color.GREEN) 1 >>> len(white) 3
- __bool__(self):
Возвращает True, если какие-либо элементы отмечены флагом, False в противном случае:
>>> bool(Color.GREEN) True >>> bool(white) True >>> black = Color(0) >>> bool(black) False
- __or__(self, other)¶
Возвращает текущий двоичный файл флага или сопоставляется с другими:
>>> Color.RED | Color.GREEN <Color.RED|GREEN: 3>
- __and__(self, other)¶
Возвращает текущий двоичный файл с флагом и сопоставляется с другими:
>>> purple & white <Color.RED|BLUE: 5> >>> purple & Color.GREEN <Color: 0>
- __xor__(self, other)¶
Возвращает двоичный код текущего флага, преобразованный в xor с помощью других:
>>> purple ^ white <Color.GREEN: 2> >>> purple ^ Color.GREEN <Color.RED|GREEN|BLUE: 7>
- __invert__(self):
Возвращает все флаги в type(self), которых нет в self:
>>> ~white <Color: 0> >>> ~purple <Color.GREEN: 2> >>> ~Color.RED <Color.GREEN|BLUE: 6>
- _numeric_repr_()¶
Функция, используемая для форматирования всех оставшихся безымянных числовых значений. По умолчанию используется значение repr; обычно используются варианты
hex()
иoct()
.
Примечание
Использование
auto
сFlag
приводит к получению целых чисел, являющихся степенями двойки, начиная с1
.Изменено в версии 3.11: Изменено значение repr() для флагов с нулевым значением. Теперь это:
>>> Color(0) <Color: 0>
- class enum.IntFlag¶
IntFlag - это то же самое, что Flag, но его элементы также являются целыми числами и могут использоваться везде, где можно использовать целое число.
>>> from enum import IntFlag, auto >>> class Color(IntFlag): ... RED = auto() ... GREEN = auto() ... BLUE = auto() >>> Color.RED & 2 <Color: 0> >>> Color.RED | 2 <Color.RED|GREEN: 3>
Если какая-либо целочисленная операция выполняется с элементом IntFlag, результатом будет не IntFlag:
>>> Color.RED + 2 3
Если операция Flag выполняется с элементом IntFlag и:
результатом является допустимый IntFlag: возвращается IntFlag
результатом является недопустимый IntFlag: результат зависит от настройки FlagBoundary
Изменено значение repr() для неназванных флагов с нулевым значением. Теперь это:
>>> Color(0) <Color: 0>
Примечание
Использование
auto
сIntFlag
приводит к получению целых чисел, являющихся степенями двойки, начиная с1
.Изменено в версии 3.11:
__str__()
теперьint.__str__()
для лучшей поддержки варианта использования *замены существующих констант.__format__()
уже былint.__format__()
по той же причине.Инверсия
IntFlag
теперь возвращает положительное значение, которое является объединением всех флагов, не входящих в данный флаг, а не отрицательное значение. Это соответствует существующему поведениюFlag
.
- class enum.ReprEnum¶
ReprEnum
используетrepr()
изEnum
, ноstr()
из смешанного типа данных:Наследовать от
ReprEnum
, чтобы сохранитьstr()
/format()
смешанного типа данных вместо использованияEnum
-по умолчаниюstr()
.Добавлено в версии 3.11.
- class enum.EnumCheck¶
EnumCheck содержит параметры, используемые декоратором
verify()
для обеспечения различных ограничений; сбой ограничений приводит кValueError
.- UNIQUE¶
Убедитесь, что каждое значение имеет только одно имя:
>>> from enum import Enum, verify, UNIQUE >>> @verify(UNIQUE) ... class Color(Enum): ... RED = 1 ... GREEN = 2 ... BLUE = 3 ... CRIMSON = 1 Traceback (most recent call last): ... ValueError: aliases found in <enum 'Color'>: CRIMSON -> RED
- CONTINUOUS¶
Убедитесь, что между элементом с наименьшим значением и элементом с наибольшим значением нет пропущенных значений:
>>> from enum import Enum, verify, CONTINUOUS >>> @verify(CONTINUOUS) ... class Color(Enum): ... RED = 1 ... GREEN = 2 ... BLUE = 5 Traceback (most recent call last): ... ValueError: invalid enum 'Color': missing values 3, 4
- NAMED_FLAGS¶
Убедитесь, что все группы флагов/маски содержат только именованные флаги - это полезно, когда значения указаны, а не генерируются с помощью
auto()
:>>> from enum import Flag, verify, NAMED_FLAGS >>> @verify(NAMED_FLAGS) ... class Color(Flag): ... RED = 1 ... GREEN = 2 ... BLUE = 4 ... WHITE = 15 ... NEON = 31 Traceback (most recent call last): ... ValueError: invalid Flag 'Color': aliases WHITE and NEON are missing combined values of 0x18 [use enum.show_flag_values(value) for details]
Примечание
CONTINUOUS и NAMED_FLAGS предназначены для работы с целочисленными элементами.
Добавлено в версии 3.11.
- class enum.FlagBoundary¶
FlagBoundary управляет тем, как значения, выходящие за пределы диапазона, обрабатываются в Flag и его подклассах.
- STRICT¶
Значения, выходящие за пределы диапазона, приводят к появлению
ValueError
. Это значение по умолчанию дляFlag
:>>> from enum import Flag, STRICT, auto >>> class StrictFlag(Flag, boundary=STRICT): ... RED = auto() ... GREEN = auto() ... BLUE = auto() >>> StrictFlag(2**2 + 2**4) Traceback (most recent call last): ... ValueError: <flag 'StrictFlag'> invalid value 20 given 0b0 10100 allowed 0b0 00111
- CONFORM¶
Недопустимые значения, выходящие за пределы диапазона, удаляются, оставляя допустимое значение Flag:
>>> from enum import Flag, CONFORM, auto >>> class ConformFlag(Flag, boundary=CONFORM): ... RED = auto() ... GREEN = auto() ... BLUE = auto() >>> ConformFlag(2**2 + 2**4) <ConformFlag.BLUE: 4>
- EJECT¶
Значения, находящиеся за пределами диапазона, теряют свою принадлежность к Флагу и возвращаются к
int
.>>> from enum import Flag, EJECT, auto >>> class EjectFlag(Flag, boundary=EJECT): ... RED = auto() ... GREEN = auto() ... BLUE = auto() >>> EjectFlag(2**2 + 2**4) 20
- KEEP¶
Значения, выходящие за пределы диапазона, сохраняются, а принадлежность к Флагу сохраняется. Это значение по умолчанию для
IntFlag
:>>> from enum import Flag, KEEP, auto >>> class KeepFlag(Flag, boundary=KEEP): ... RED = auto() ... GREEN = auto() ... BLUE = auto() >>> KeepFlag(2**2 + 2**4) <KeepFlag.BLUE|16: 20>
Добавлено в версии 3.11.
Поддерживаемые имена __dunder__
¶
__members__
- это упорядоченное отображение элементов member_name
:member
только для чтения. Оно доступно только в классе.
__new__()
, если указано, должно создавать и возвращать элементы перечисления; также рекомендуется соответствующим образом задать значение элемента _value_
. После создания всех элементов оно больше не используется.
Поддерживаемые имена _sunder_
¶
_name_
– имя участника_value_
– значение элемента; может быть задано в виде__new__
_missing_()
– функция поиска, используемая, когда значение не найдено; может быть переопределена_ignore_
– список имен, либо в видеlist
, либо в видеstr
, которые не будут преобразованы в члены и будут удалены из конечного класса_order_
– больше не используется, сохранен для обеспечения обратной совместимости (атрибут class, удален при создании класса)_generate_next_value_()
– используется для получения соответствующего значения для элемента перечисления; может быть переопределен
Добавлено в версии 3.6: _missing_
, _order_
, _generate_next_value_
Добавлено в версии 3.7: _ignore_
Коммунальные службы и декораторы¶
- class enum.auto¶
вместо значения может быть использовано значение auto. Если оно используется, механизм Enum вызовет значение Enum
_generate_next_value_()
, чтобы получить соответствующее значение. Для Enum и IntEnum подходящим значением будет последнее значение плюс единица; для Flag и IntFlag это будет первая степень двойки, превышающая наибольшее значение; для StrEnum это будет вариант имени элемента в нижнем регистре. Необходимо соблюдать осторожность при смешивании auto() с заданными вручную значениями.автоматически экземпляры разрешаются только на верхнем уровне назначения:
FIRST = auto()
будет работать (функция auto() заменена на1
);SECOND = auto(), -2
будет работать (auto заменяется на2
, поэтому2, -2
используется для создания элемента перечисленияSECOND
;THREE = [auto(), -3]
не будет * работать (<auto instance>, -3
используется для создания элемента перечисленияTHREE
)
Изменено в версии 3.11.1: В предыдущих версиях для правильной работы в строке назначения должно было быть только
auto()
._generate_next_value_
может быть переопределен для настройки значений, используемых auto.Примечание
в версии 3.13 значение по умолчанию
_generate_next_value_
всегда будет возвращать наибольшее значение элемента, увеличенное на 1, и завершится ошибкой, если какой-либо элемент является несовместимым типом.
- @enum.property¶
Средство оформления, аналогичное встроенному свойству property, но предназначенное специально для перечислений. Оно позволяет атрибутам элементов иметь те же имена, что и у самих элементов.
Примечание
свойство * и элемент должны быть определены в отдельных классах; например, атрибуты value и name определены в классе Enum, а подклассы Enum могут определять элементы с именами
value
иname
.Добавлено в версии 3.11.
- @enum.unique¶
Декоратор
class
, созданный специально для перечислений. Он выполняет поиск в перечислении__members__
, собирая все найденные псевдонимы; если таковые будут найдены,ValueError
вызывается с подробностями:>>> from enum import Enum, unique >>> @unique ... class Mistake(Enum): ... ONE = 1 ... TWO = 2 ... THREE = 3 ... FOUR = 3 ... Traceback (most recent call last): ... ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE
- @enum.verify¶
Декоратор
class
предназначен специально для перечислений. Элементы изEnumCheck
используются для указания того, какие ограничения следует проверять в оформленном перечислении.Добавлено в версии 3.11.
- @enum.member¶
Декоратор для использования в перечислениях: его цель станет членом.
Добавлено в версии 3.11.
- @enum.nonmember¶
Декоратор для использования в перечислениях: его целевой объект не станет участником.
Добавлено в версии 3.11.
- @enum.global_enum¶
Декоратор для изменения
str()
иrepr()
в перечислении, чтобы показать его элементы как принадлежащие модулю, а не его классу. Следует использовать только тогда, когда элементы перечисления экспортируются в глобальное пространство имен модуля (пример смотрите вre.RegexFlag
).Добавлено в версии 3.11.
- enum.show_flag_values(value)¶
Возвращает список всех целых чисел в степени двойки, содержащихся в флаге value.
Добавлено в версии 3.11.
Записи¶
Эти три типа перечислений предназначены для замены существующих целочисленных и строковых значений; как таковые, они имеют дополнительные ограничения:
__str__
использует значение, а не имя элемента перечисления
__format__
, поскольку он использует__str__
, также будет использовать значение элемента перечисления вместо его имениЕсли вам не нужны эти ограничения, вы можете либо создать свой собственный базовый класс, введя тип
int
илиstr
самостоятельно:>>> from enum import Enum >>> class MyIntEnum(int, Enum): ... passили вы можете переназначить соответствующий
str()
и т.д. в вашем перечислении:>>> from enum import Enum, IntEnum >>> class MyIntEnum(IntEnum): ... __str__ = Enum.__str__