Сообщить об ошибке.

Подробности реализации модуля enum Python.

В разделе перечислены главные отличия перечисления модуля enum

У перечислений модуля enum есть собственный метакласс, который влияет на многие аспекты как производных классов Enum, так и их экземпляров (членов).

Классы enum.Enum.

Метакласс EnumMeta отвечает за предоставление __contains__(), __dir__(), __iter__() и других магических методов, которые позволяют делать с классом enum.Enum вещи, которые не работают в типичном классе, например:

>>> from enum import Enum
>>> class ColorEnum(Enum):
...     RED = 1
...     GREEN = 2
...     BLUE = 3
... 
# простой класс
>>> class Color():
...     RED = 1
...     GREEN = 2
...     BLUE = 3
...           
>>> list(ColorEnum)
# [<ColorEnum.RED: 1>, <ColorEnum.GREEN: 2>, <ColorEnum.BLUE: 3>]
>>> list(Color)
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: 'type' object is not iterable

Метакласс EnumMeta отвечает за обеспечение правильности различных других методов в классе Enum. Например, __new__(), __getnewargs__(), __str__() и __repr__().

Члены перечисления (также известные как экземпляры класса).

Самое интересное в членах Enum - это то, что они одиночки. Метакласс EnumMeta создает их все, пока он создает сам класс Enum, а затем помещает пользовательский __new__() на место, дабы гарантировать, что новые экземпляры никогда не будут созданы, путем возврата только существующих экземпляров членов.


Подробности реализации модуля enum.

Ограниченное создание подклассов enum.Enum.

Новый класс Enum должен иметь один базовый класс Enum, до одного конкретного типа данных и столько классов примесей на основе объектов, сколько необходимо. Порядок этих базовых классов:

class EnumName([mix-in, ...,] [data-type,] base-enum):
    pass

Кроме того, создание подкласса перечисления разрешено, только если перечисление не определяет никаких членов. Итак, это запрещено:

>>> class MoreColor(Color):
...     PINK = 17
...
# Traceback (most recent call last):
...
# TypeError: Cannot extend enumerations

Но это разрешено:

>>> class Foo(Enum):
...     def some_behavior(self):
...         pass
...
>>> class Bar(Foo):
...     HAPPY = 1
...     SAD = 2
...

Разрешение создания подклассов перечислений, определяющих члены, приведет к нарушению некоторых важных инвариантов типов и экземпляров. С другой стороны, имеет смысл разрешить несколько общих действий для группы перечислений. Смотрите пример OrderedEnum.

Pickling enum.Enum.

Перечисления enum.Enum могут быть pickling и unpickling:

>>> from test.test_enum import Fruit
>>> from pickle import dumps, loads
>>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
True

Применяются обычные ограничения для pickling: выбираемые перечисления должны быть определены на верхнем уровне модуля, поскольку для распаковки требуется, чтобы они были импортированы из этого модуля.

Примечание. С версией протокола pickle 4 можно легко выделить перечисления, вложенные в другие классы.

Можно изменить способ выделения/извлечения членов enum.Enum путем определения __reduce_ex__() в классе перечисления.

Поддержка __dunder__ имен.

__members__ - это упорядоченное отображение (словарь) элементов member_name:member только для чтения. Доступно только в классе.

__new__(), если он указан, то должен создавать и возвращать члены перечисления. Это также неплохая идея, чтобы установить _value_ соответствующим образом. Как только все члены созданы, он больше не используется.

Поддержка _sunder_ имен.

  • _name_ - имя участника
  • _value_ - значение члена; можно установить/изменить в __new__().
  • _missing_ - функция поиска, используемая, когда значение не найдено. Может быть отменена.
  • _ignore_ - список имен в виде списка или строки, которые не будут преобразованы в члены и будут удалены из последнего класса.
  • _order_ - используется в коде Python 2/3 для обеспечения согласованности порядка членов (атрибут класса, удаляется во время создания класса)
  • generatenextvalue - используется функциональным API и автоматически для получения подходящего значения для члена перечисления; . Может быть отменено.

Новое в Python 3.6: _missing_, _order_, _generate_next_value_.

Новое в Python 3.7: _ignore_.

Чтобы помочь синхронизировать код Python 2/Python 3, можно предоставить атрибут _order_. Он будет проверен по фактическому порядку перечисления и вызовет ошибку, если они не совпадают:

>>> class Color(Enum):
...     _order_ = 'RED GREEN BLUE'
...     RED = 1
...     BLUE = 3
...     GREEN = 2
...
# Traceback (most recent call last):
...
# TypeError: member order does not match _order_

Тип члена перечисления.

Члены Enum являются экземплярами своего класса Enum и обычно доступны как EnumClass.member. При определенных обстоятельствах к ним также можно получить доступ как EnumClass.member.member, но вы никогда не должны этого делать! Так как этот поиск может завершиться неудачно или что еще хуже, вернуть что-то, кроме члена Enum, который вы ищете. Это еще одна веская причина использовать all-uppercase для имен членов:

>>> class FieldTypes(Enum):
...     name = 0
...     value = 1
...     size = 2
...
>>> FieldTypes.value.size
# <FieldTypes.size: 2>
>>> FieldTypes.size.value
# 2

Логическое значение классов и членов Enum.

Члены Enum, которые смешиваются с типами, отличными от Enum (такими как int, str и т. д.), оцениваются в соответствии с правилами смешанного типа. В противном случае все члены оцениваются как True. Чтобы сделать логическую оценку собственного Enum зависящей от значения члена, добавьте в класс следующее:

def __bool__(self):
    return bool(self.value)

Классы Enum всегда оцениваются как True.

Классы перечислений с дополнительными методами.

Если предоставить своему подклассу Enum дополнительные методы, такие как класс Planet (в разделе "Интересные примеры классов перечислений"), то эти методы будут отображаться в функции dir() у членов перечисления, но не в самом классе:

>>> dir(Planet)
# ['EARTH', 'JUPITER', 'MARS', 
# 'MERCURY', 'NEPTUNE', 'SATURN', 
# 'URANUS', 'VENUS', '__class__',
# '__doc__', '__members__', '__module__']
>>> dir(Planet.EARTH)
# ['__class__', '__doc__', '__module__', 
# 'name', 'surface_gravity', 'value']

Объединение членов класса enum.Flag.

Если комбинация членов Flag не имеет имени, то функция repr() будет включать все именованные флаги и все именованные комбинации флагов, которые находятся в значении:

>>> class Color(Flag):
...     RED = auto()
...     GREEN = auto()
...     BLUE = auto()
...     MAGENTA = RED | BLUE
...     YELLOW = RED | GREEN
...     CYAN = GREEN | BLUE
...
>>> Color(3)  # named combination
# <Color.YELLOW: 3>
>>> Color(7)      # not named combination
# <Color.CYAN|MAGENTA|BLUE|YELLOW|GREEN|RED: 7>