enum.md
1> **Источник:** https://python-all.ru/3.7/library/enum.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# [`enum`](https://python-all.ru/3.7/library/enum.html#module-enum) – Поддержка перечислений89Новое в версии 3.4.1011**Исходный код:** [Lib/enum.py](https://python-all.ru/src/3.7/Lib/enum.py)1213---1415Перечисление – это набор символических имён (членов), привязанных к уникальным постоянным значениям. Внутри перечисления члены можно сравнивать по идентичности, а само перечисление можно перебирать.1617## Содержимое модуля1819Этот модуль определяет четыре класса перечислений, которые можно использовать для определения уникальных наборов имён и значений: [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum), [`IntEnum`](https://python-all.ru/3.7/library/enum.html#enum.IntEnum), [`Flag`](https://python-all.ru/3.7/library/enum.html#enum.Flag) и [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag). Также он определяет один декоратор [`unique()`](https://python-all.ru/3.7/library/enum.html#enum.unique) и один вспомогательный класс [`auto`](https://python-all.ru/3.7/library/enum.html#enum.auto).2021#### `class enum.Enum`2223Базовый класс для создания перечислимых констант. См. раздел [Функциональный API](https://python-all.ru/3.7/library/enum.html#functional-api) для альтернативного синтаксиса создания.2425#### `class enum.IntEnum`2627Базовый класс для создания перечислимых констант, которые также являются подклассами [`int`](https://python-all.ru/3.7/library/functions.html#int).2829#### `class enum.IntFlag`3031Базовый класс для создания перечислимых констант, которые можно комбинировать с помощью побитовых операторов, не теряя принадлежности к [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag). Члены [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag) также являются подклассами [`int`](https://python-all.ru/3.7/library/functions.html#int).3233#### `class enum.Flag`3435Базовый класс для создания перечисляемых констант, которые можно комбинировать с помощью побитовых операций без потери их принадлежности к [`Flag`](https://python-all.ru/3.7/library/enum.html#enum.Flag).3637#### `enum.unique()`3839Декоратор класса перечисления, который гарантирует, что каждому значению соответствует только одно имя.4041#### `class enum.auto`4243Экземпляры заменяются подходящим значением для элементов Enum. Начальное значение – 1.4445Новое в версии 3.6: `Flag`, `IntFlag`, `auto`4647## Создание перечисления4849Перечисления создаются с использованием синтаксиса [`class`](https://python-all.ru/3.7/reference/compound_stmts.html#class), что делает их легко читаемыми и удобными для записи. Альтернативный метод создания описан в [Функциональный API](https://python-all.ru/3.7/library/enum.html#functional-api). Чтобы определить перечисление, создайте подкласс [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) следующим образом:5051```python52>>> from enum import Enum53>>> class Color(Enum):54... RED = 155... GREEN = 256... BLUE = 357...58```5960> **Примечание**61>62> Значения членов Enum63>64> Значения членов могут быть любыми: [`int`](https://python-all.ru/3.7/library/functions.html#int), [`str`](https://python-all.ru/3.7/library/stdtypes.html#str) и т.д. Если точное значение неважно, можно использовать экземпляры [`auto`](https://python-all.ru/3.7/library/enum.html#enum.auto), и подходящее значение будет выбрано автоматически. Следует соблюдать осторожность при смешивании [`auto`](https://python-all.ru/3.7/library/enum.html#enum.auto) с другими значениями.6566> **Примечание**67>68> Терминология69>70> - Класс `Color` является *перечислением* (или *enum*)71> - Атрибуты `Color.RED`, `Color.GREEN` и т.д. являются *членами перечисления* (или *членами перечисления*) и по сути являются константами.72> - Члены перечисления имеют *имена* и *значения* (имя `Color.RED` – `RED`, значение `Color.BLUE` – `3` и т.д.)7374> **Примечание**75>76> Хотя для создания перечислений мы используем синтаксис [`class`](https://python-all.ru/3.7/reference/compound_stmts.html#class), перечисления не являются обычными классами Python. Подробнее см. [Чем отличаются перечисления?](https://python-all.ru/3.7/library/enum.html#how-are-enums-different).7778Члены перечисления имеют удобочитаемые строковые представления:7980```python81>>> print(Color.RED)82Color.RED83```8485…в то время как их `repr` содержит больше информации:8687```python88>>> print(repr(Color.RED))89<Color.RED: 1>90```9192*Тип* члена перечисления – это перечисление, к которому он принадлежит:9394```python95>>> type(Color.RED)96<enum 'Color'>97>>> isinstance(Color.GREEN, Color)98True99>>>100```101102Члены перечисления также имеют свойство, содержащее только их имя:103104```python105>>> print(Color.RED.name)106RED107```108109Перечисления поддерживают итерацию в порядке определения:110111```python112>>> class Shake(Enum):113... VANILLA = 7114... CHOCOLATE = 4115... COOKIES = 9116... MINT = 3117...118>>> for shake in Shake:119... print(shake)120...121Shake.VANILLA122Shake.CHOCOLATE123Shake.COOKIES124Shake.MINT125```126127Члены перечисления хешируемы, поэтому их можно использовать в словарях и множествах:128129```python130>>> apples = {}131>>> apples[Color.RED] = 'red delicious'132>>> apples[Color.GREEN] = 'granny smith'133>>> apples == {Color.RED: 'red delicious', Color.GREEN: 'granny smith'}134True135```136137## Программный доступ к членам перечисления и их атрибутам138139Иногда бывает полезно обращаться к членам перечисления программно (например, в ситуациях, когда `Color.RED` не подходит, поскольку точный цвет неизвестен на момент написания программы). `Enum` предоставляет такой доступ:140141```python142>>> Color(1)143<Color.RED: 1>144>>> Color(3)145<Color.BLUE: 3>146```147148Если требуется обратиться к членам перечисления по *имени*, используйте доступ по ключу:149150```python151>>> Color['RED']152<Color.RED: 1>153>>> Color['GREEN']154<Color.GREEN: 2>155```156157Если есть член перечисления и требуется его `name` или `value`:158159```python160>>> member = Color.RED161>>> member.name162'RED'163>>> member.value1641165```166167## Дублирование членов и значений перечисления168169Наличие двух членов перечисления с одинаковым именем недопустимо:170171```python172>>> class Shape(Enum):173... SQUARE = 2174... SQUARE = 3175...176Traceback (most recent call last):177...178TypeError: Attempted to reuse key: 'SQUARE'179```180181Однако двум членам перечисления разрешено иметь одинаковое значение. Если два члена A и B имеют одинаковое значение (и A определён первым), то B является псевдонимом A. Поиск по значению A и B вернёт A. Поиск по имени B также вернёт A:182183```python184>>> class Shape(Enum):185... SQUARE = 2186... DIAMOND = 1187... CIRCLE = 3188... ALIAS_FOR_SQUARE = 2189...190>>> Shape.SQUARE191<Shape.SQUARE: 2>192>>> Shape.ALIAS_FOR_SQUARE193<Shape.SQUARE: 2>194>>> Shape(2)195<Shape.SQUARE: 2>196```197198> **Примечание**199>200> Попытка создать член с тем же именем, что и уже определённый атрибут (другой член, метод и т.д.), или попытка создать атрибут с тем же именем, что и член, не допускается.201202## Обеспечение уникальности значений перечисления203204По умолчанию перечисления допускают несколько имён в качестве псевдонимов для одного и того же значения. Если такое поведение нежелательно, можно использовать следующий декоратор, чтобы гарантировать, что каждое значение используется в перечислении только один раз:205206#### `@enum.unique`207208Декоратор [`class`](https://python-all.ru/3.7/reference/compound_stmts.html#class), предназначенный специально для перечислений. Он просматривает `__members__` перечисления, собирая все найденные псевдонимы; если таковые обнаружены, возбуждается [`ValueError`](https://python-all.ru/3.7/library/exceptions.html#ValueError) с подробностями.209210```python211>>> from enum import Enum, unique212>>> @unique213... class Mistake(Enum):214... ONE = 1215... TWO = 2216... THREE = 3217... FOUR = 3218...219Traceback (most recent call last):220...221ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE222```223224## Использование автоматических значений225226Если точное значение неважно, можно использовать [`auto`](https://python-all.ru/3.7/library/enum.html#enum.auto):227228```python229>>> from enum import Enum, auto230>>> class Color(Enum):231... RED = auto()232... BLUE = auto()233... GREEN = auto()234...235>>> list(Color)236[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]237```238239Значения выбираются с помощью `_generate_next_value_()`, который можно переопределить:240241```python242>>> class AutoName(Enum):243... def _generate_next_value_(name, start, count, last_values):244... return name245...246>>> class Ordinal(AutoName):247... NORTH = auto()248... SOUTH = auto()249... EAST = auto()250... WEST = auto()251...252>>> list(Ordinal)253[<Ordinal.NORTH: 'NORTH'>, <Ordinal.SOUTH: 'SOUTH'>, <Ordinal.EAST: 'EAST'>, <Ordinal.WEST: 'WEST'>]254```255256> **Примечание**257>258> Цель методов по умолчанию `_generate_next_value_()` – предоставить следующий [`int`](https://python-all.ru/3.7/library/functions.html#int) в последовательности с последним указанным [`int`](https://python-all.ru/3.7/library/functions.html#int), но то, как это делается, является деталью реализации и может измениться.259260> **Примечание**261>262> Метод `_generate_next_value_()` должен быть определён до любых членов.263264## Перебор265266Перебор членов перечисления не включает псевдонимы:267268```python269>>> list(Shape)270[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]271```272273Специальный атрибут `__members__` – это упорядоченный словарь, сопоставляющий имена с элементами. Он включает все имена, определённые в перечислении, включая псевдонимы:274275```python276>>> for name, member in Shape.__members__.items():277... name, member278...279('SQUARE', <Shape.SQUARE: 2>)280('DIAMOND', <Shape.DIAMOND: 1>)281('CIRCLE', <Shape.CIRCLE: 3>)282('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)283```284285Атрибут `__members__` можно использовать для детального программного доступа к членам перечисления. Например, для поиска всех псевдонимов:286287```python288>>> [name for name, member in Shape.__members__.items() if member.name != name]289['ALIAS_FOR_SQUARE']290```291292## Сравнения293294Члены перечисления сравниваются по идентичности:295296```python297>>> Color.RED is Color.RED298True299>>> Color.RED is Color.BLUE300False301>>> Color.RED is not Color.BLUE302True303```304305Упорядоченные сравнения между значениями перечисления *не* поддерживаются. Члены перечисления – не целые числа (но см. [IntEnum](https://python-all.ru/3.7/library/enum.html#intenum) ниже):306307```python308>>> Color.RED < Color.BLUE309Traceback (most recent call last):310 File "<stdin>", line 1, in <module>311TypeError: '<' not supported between instances of 'Color' and 'Color'312```313314Однако сравнения на равенство определены:315316```python317>>> Color.BLUE == Color.RED318False319>>> Color.BLUE != Color.RED320True321>>> Color.BLUE == Color.BLUE322True323```324325Сравнения со значениями, не являющимися перечислениями, всегда дают результат «не равно» (опять же, [`IntEnum`](https://python-all.ru/3.7/library/enum.html#enum.IntEnum) был явно спроектирован для другого поведения, см. ниже):326327```python328>>> Color.BLUE == 2329False330```331332## Допустимые члены и атрибуты перечислений333334В примерах выше для значений перечислений используются целые числа. Использование целых чисел – это кратко и удобно (и предусмотрено по умолчанию [функциональным API](https://python-all.ru/3.7/library/enum.html#functional-api)), но не является строгим требованием. В подавляющем большинстве случаев не важно, каково фактическое значение элемента перечисления. Но если значение *является* важным, перечисления могут иметь произвольные значения.335336Перечисления – это классы Python и могут иметь обычные методы и специальные методы. Если есть такое перечисление:337338```python339>>> class Mood(Enum):340... FUNKY = 1341... HAPPY = 3342...343... def describe(self):344... # self – это член перечисления345... return self.name, self.value346...347... def __str__(self):348... return 'my custom str! {0}'.format(self.value)349...350... @classmethod351... def favorite_mood(cls):352... # cls здесь – это перечисление353... return cls.HAPPY354...355```356357Тогда:358359```python360>>> Mood.favorite_mood()361<Mood.HAPPY: 3>362>>> Mood.HAPPY.describe()363('HAPPY', 3)364>>> str(Mood.FUNKY)365'my custom str! 1'366```367368Правила допустимого таковы: имена, которые начинаются и заканчиваются одним подчёркиванием, зарезервированы для enum и не могут использоваться; все остальные атрибуты, определённые внутри перечисления, становятся его членами, за исключением специальных методов ([`__str__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__str__), [`__add__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__add__) и т.д.), дескрипторов (методы тоже являются дескрипторами) и имён переменных, перечисленных в `_ignore_`.369370Примечание: если в перечислении определены [`__new__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__new__) и/или [`__init__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__init__), то все значения, переданные элементу перечисления, будут переданы в эти методы. В качестве примера см. [Planet](https://python-all.ru/3.7/library/enum.html#planet).371372## Ограниченное создание подклассов Enum373374Новый класс [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) должен иметь один базовый класс Enum, не более одного конкретного типа данных и столько [`object`](https://python-all.ru/3.7/library/functions.html#object)-основанных классов-примесей, сколько необходимо. Порядок этих базовых классов:375376```python377class EnumName([mix-in, ...,] [data-type,] base-enum):378 pass379```380381Также создание подкласса перечисления разрешено только в том случае, если перечисление не определяет никаких членов. Поэтому это запрещено:382383```python384>>> class MoreColor(Color):385... PINK = 17386...387Traceback (most recent call last):388...389TypeError: Cannot extend enumerations390```391392Но это разрешено:393394```python395>>> class Foo(Enum):396... def some_behavior(self):397... pass398...399>>> class Bar(Foo):400... HAPPY = 1401... SAD = 2402...403```404405Разрешение создания подклассов перечислений, определяющих члены, привело бы к нарушению некоторых важных инвариантов типов и экземпляров. С другой стороны, имеет смысл разрешить общее поведение для группы перечислений. (Пример см. в [OrderedEnum](https://python-all.ru/3.7/library/enum.html#orderedenum).)406407## Пиклинг408409Перечисления могут быть упакованы и распакованы с помощью модуля pickle.410411```python412>>> from test.test_enum import Fruit413>>> from pickle import dumps, loads414>>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))415True416```417418Обычные ограничения для упаковки с помощью модуля pickle применяются: перечисления, которые можно упаковать, должны быть определены на верхнем уровне модуля, так как для распаковки их нужно импортировать из этого модуля.419420> **Примечание**421>422> С протоколом pickle версии 4 можно легко упаковывать перечисления, вложенные в другие классы.423424Можно изменить способ сериализации/десериализации членов Enum, определив [`__reduce_ex__()`](https://python-all.ru/3.7/library/pickle.html#object.__reduce_ex__) в классе перечисления.425426## Функциональное API427428Класс [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) является вызываемым и предоставляет следующее функциональное API:429430```python431>>> Animal = Enum('Animal', 'ANT BEE CAT DOG')432>>> Animal433<enum 'Animal'>434>>> Animal.ANT435<Animal.ANT: 1>436>>> Animal.ANT.value4371438>>> list(Animal)439[<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]440```441442Семантика этого API напоминает [`namedtuple`](https://python-all.ru/3.7/library/collections.html#collections.namedtuple). Первый аргумент вызова [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) – это имя перечисления.443444Второй аргумент – это *источник* имён членов перечисления. Это может быть строка имён, разделённых пробелами, последовательность имён, последовательность двухэлементных кортежей с парами ключ/значение или отображение (например, словарь) имён на значения. Последние два варианта позволяют присваивать произвольные значения перечислениям; остальные автоматически присваивают увеличивающиеся целые числа, начиная с 1 (используйте параметр `start` для указания другого начального значения). Возвращается новый класс, производный от [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum). Другими словами, приведённое выше присваивание `Animal` эквивалентно:445446```python447>>> class Animal(Enum):448... ANT = 1449... BEE = 2450... CAT = 3451... DOG = 4452...453```454455Причина, по которой по умолчанию используется `1`, а не `0`, заключается в том, что `0` равно `False` с точки зрения булевой логики, но все члены перечисления вычисляются в `True`.456457Сериализация перечислений, созданных с помощью функционального API, может быть сложной, поскольку для определения модуля, в котором создаётся перечисление, используются детали реализации стека вызовов (например, это не сработает, если использовать вспомогательную функцию в отдельном модуле, а также может не работать в IronPython или Jython). Решение – явно указать имя модуля следующим образом:458459```python460>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)461```462463> **Предупреждение**464>465> Если `module` не указан, и Enum не может его определить, новые члены Enum не будут поддерживать распаковку; чтобы ошибки были ближе к источнику, pickling будет отключён.466467Новый протокол pickle 4 также в некоторых обстоятельствах полагается на то, что [`__qualname__`](https://python-all.ru/3.7/library/stdtypes.html#definition.__qualname__) установлен в расположение, где pickle сможет найти класс. Например, если класс стал доступен в классе SomeData в глобальной области видимости:468469```python470>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')471```472473Полная сигнатура:474475```python476Enum(value='NewEnumName', names=<...>, *, module='...', qualname='...', type=<mixed-in class>, start=1)477```478479**значение**480481Что новый класс Enum запишет в качестве своего имени.482483**имена**484485Члены перечисления. Это может быть строка, разделённая пробелами или запятыми (значения будут начинаться с 1, если не указано иное):486487```python488'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'489```490491или итератор имён:492493```python494['RED', 'GREEN', 'BLUE']495```496497или итератор пар (имя, значение):498499```python500[('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]501```502503или отображение:504505```python506{'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}507```508509**модуль**510511имя модуля, в котором находится новый класс Enum.512513**qualname**514515где в модуле находится новый класс Enum.516517**тип**518519тип, который следует примешать к новому классу Enum.520521**start**522523число, с которого начинать отсчёт, если переданы только имена.524525Изменено в версии 3.5: Добавлен параметр *start*.526527## Производные перечисления528529### IntEnum530531Первая разновидность [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) также является подклассом [`int`](https://python-all.ru/3.7/library/functions.html#int). Элементы [`IntEnum`](https://python-all.ru/3.7/library/enum.html#enum.IntEnum) можно сравнивать с целыми числами; соответственно, целочисленные перечисления разных типов также можно сравнивать друг с другом:532533```python534>>> from enum import IntEnum535>>> class Shape(IntEnum):536... CIRCLE = 1537... SQUARE = 2538...539>>> class Request(IntEnum):540... POST = 1541... GET = 2542...543>>> Shape == 1544False545>>> Shape.CIRCLE == 1546True547>>> Shape.CIRCLE == Request.POST548True549```550551Однако их по-прежнему нельзя сравнивать со стандартными перечислениями [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum):552553```python554>>> class Shape(IntEnum):555... CIRCLE = 1556... SQUARE = 2557...558>>> class Color(Enum):559... RED = 1560... GREEN = 2561...562>>> Shape.CIRCLE == Color.RED563False564```565566Значения [`IntEnum`](https://python-all.ru/3.7/library/enum.html#enum.IntEnum) ведут себя как целые числа и в других ожидаемых аспектах:567568```python569>>> int(Shape.CIRCLE)5701571>>> ['a', 'b', 'c'][Shape.CIRCLE]572'b'573>>> [i for i in range(Shape.SQUARE)]574[0, 1]575```576577### IntFlag578579Следующая вариация [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum), а именно [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag), также основана на [`int`](https://python-all.ru/3.7/library/functions.html#int). Разница в том, что члены [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag) можно объединять с помощью побитовых операторов (&, |, ^, ~), и результат всё ещё остаётся членом [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag). Однако, как следует из названия, члены [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag) также являются подклассами [`int`](https://python-all.ru/3.7/library/functions.html#int) и могут использоваться везде, где используется [`int`](https://python-all.ru/3.7/library/functions.html#int). Любая операция над членом [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag), кроме побитовых операций, приведёт к потере его принадлежности к [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag).580581Новое в версии 3.6.582583Пример класса [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag):584585```python586>>> from enum import IntFlag587>>> class Perm(IntFlag):588... R = 4589... W = 2590... X = 1591...592>>> Perm.R | Perm.W593<Perm.R|W: 6>594>>> Perm.R + Perm.W5956596>>> RW = Perm.R | Perm.W597>>> Perm.R in RW598True599```600601Также можно давать имена комбинациям:602603```python604>>> class Perm(IntFlag):605... R = 4606... W = 2607... X = 1608... RWX = 7609>>> Perm.RWX610<Perm.RWX: 7>611>>> ~Perm.RWX612<Perm.-8: -8>613```614615Ещё одно важное отличие между [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag) и [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) в том, что если ни один флаг не установлен (значение равно 0), то его логическое значение – [`False`](https://python-all.ru/3.7/library/constants.html#False):616617```python618>>> Perm.R & Perm.X619<Perm.0: 0>620>>> bool(Perm.R & Perm.X)621False622```623624Поскольку члены [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag) также являются подклассами [`int`](https://python-all.ru/3.7/library/functions.html#int), их можно объединять с ними:625626```python627>>> Perm.X | 8628<Perm.8|X: 9>629```630631### Flag632633Последняя разновидность – [`Flag`](https://python-all.ru/3.7/library/enum.html#enum.Flag). Как и [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag), элементы [`Flag`](https://python-all.ru/3.7/library/enum.html#enum.Flag) можно комбинировать с помощью побитовых операторов (&, |, ^, ~). В отличие от [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag), их нельзя комбинировать или сравнивать ни с каким другим перечислением [`Flag`](https://python-all.ru/3.7/library/enum.html#enum.Flag), а также с [`int`](https://python-all.ru/3.7/library/functions.html#int). Хотя можно задавать значения напрямую, рекомендуется использовать [`auto`](https://python-all.ru/3.7/library/enum.html#enum.auto) в качестве значения и позволить [`Flag`](https://python-all.ru/3.7/library/enum.html#enum.Flag) выбрать подходящее значение.634635Новое в версии 3.6.636637Как и в случае с [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag), если комбинация элементов [`Flag`](https://python-all.ru/3.7/library/enum.html#enum.Flag) не содержит установленных флагов, логическое значение равно [`False`](https://python-all.ru/3.7/library/constants.html#False):638639```python640>>> from enum import Flag, auto641>>> class Color(Flag):642... RED = auto()643... BLUE = auto()644... GREEN = auto()645...646>>> Color.RED & Color.GREEN647<Color.0: 0>648>>> bool(Color.RED & Color.GREEN)649False650```651652Отдельные флаги должны иметь значения, являющиеся степенями двойки (1, 2, 4, 8, …), в то время как комбинации флагов – нет:653654```python655>>> class Color(Flag):656... RED = auto()657... BLUE = auto()658... GREEN = auto()659... WHITE = RED | BLUE | GREEN660...661>>> Color.WHITE662<Color.WHITE: 7>663```664665Присвоение имени условию «флаги не установлены» не меняет его логическое значение:666667```python668>>> class Color(Flag):669... BLACK = 0670... RED = auto()671... BLUE = auto()672... GREEN = auto()673...674>>> Color.BLACK675<Color.BLACK: 0>676>>> bool(Color.BLACK)677False678```679680> **Примечание**681>682> Для большинства нового кода настоятельно рекомендуются [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) и [`Flag`](https://python-all.ru/3.7/library/enum.html#enum.Flag), поскольку [`IntEnum`](https://python-all.ru/3.7/library/enum.html#enum.IntEnum) и [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag) нарушают некоторые семантические обещания перечисления (будучи сравнимыми с целыми числами, а значит, по транзитивности, и с другими не связанными перечислениями). [`IntEnum`](https://python-all.ru/3.7/library/enum.html#enum.IntEnum) и [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag) следует использовать только в тех случаях, когда [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) и [`Flag`](https://python-all.ru/3.7/library/enum.html#enum.Flag) не подходят; например, при замене целочисленных констант на перечисления или для взаимодействия с другими системами.683684### Другие685686Хотя [`IntEnum`](https://python-all.ru/3.7/library/enum.html#enum.IntEnum) является частью модуля [`enum`](https://python-all.ru/3.7/library/enum.html#module-enum), его очень просто реализовать самостоятельно:687688```python689class IntEnum(int, Enum):690 pass691```692693Это показывает, как можно определить подобные производные перечисления; например, `StrEnum`, в который примешивается [`str`](https://python-all.ru/3.7/library/stdtypes.html#str) вместо [`int`](https://python-all.ru/3.7/library/functions.html#int).694695Некоторые правила:6966971. При создании подкласса [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) типы-примеси должны располагаться перед самим [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) в последовательности базовых классов, как в [`IntEnum`](https://python-all.ru/3.7/library/enum.html#enum.IntEnum) примере выше.6982. Хотя [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) может содержать элементы любого типа, как только к нему примешивается дополнительный тип, все элементы должны иметь значения этого типа, например [`int`](https://python-all.ru/3.7/library/functions.html#int) выше. Это ограничение не распространяется на примеси, которые только добавляют методы и не указывают другой тип данных, такие как [`int`](https://python-all.ru/3.7/library/functions.html#int) или [`str`](https://python-all.ru/3.7/library/stdtypes.html#str).6993. При примешивании другого типа данных атрибут `value` *отличается* от самого члена перечисления, хотя он эквивалентен и будет равным при сравнении.7004. Форматирование в стиле %: *%s* и *%r* вызывают методы [`__str__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__str__) и [`__repr__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__repr__) класса [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) соответственно; другие коды (например, *%i* или *%h* для IntEnum) обрабатывают член перечисления как его примешанный тип.7015. [Форматированные строковые литералы](https://python-all.ru/3.7/reference/lexical_analysis.html#f-strings), [`str.format()`](https://python-all.ru/3.7/library/stdtypes.html#str.format), и [`format()`](https://python-all.ru/3.7/library/functions.html#format) будут использовать [`__format__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__format__) примешанного типа. Если требуется [`str()`](https://python-all.ru/3.7/library/stdtypes.html#str) или [`repr()`](https://python-all.ru/3.7/library/functions.html#repr) класса [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum), используйте коды форматирования *!s* или *!r*.702703## Интересные примеры704705Хотя ожидается, что [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum), [`IntEnum`](https://python-all.ru/3.7/library/enum.html#enum.IntEnum), [`IntFlag`](https://python-all.ru/3.7/library/enum.html#enum.IntFlag) и [`Flag`](https://python-all.ru/3.7/library/enum.html#enum.Flag) покрывают большинство случаев использования, они не могут охватить их все. Ниже приведены рецепты для некоторых других типов перечислений, которые можно использовать напрямую или как примеры для создания собственных.706707### Пропуск значений708709Во многих случаях использования неважно, каково фактическое значение элемента перечисления. Есть несколько способов определить такой простой тип перечисления:710711- использовать экземпляры [`auto`](https://python-all.ru/3.7/library/enum.html#enum.auto) в качестве значения712- использовать экземпляры [`object`](https://python-all.ru/3.7/library/functions.html#object) в качестве значения713- использовать описательную строку в качестве значения714- использовать кортеж в качестве значения и собственный [`__new__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__new__) для замены кортежа на значение [`int`](https://python-all.ru/3.7/library/functions.html#int)715716Использование любого из этих методов показывает пользователю, что эти значения не важны, а также позволяет добавлять, удалять или переупорядочивать члены без необходимости перенумерации остальных членов.717718Какой бы метод ни был выбран, следует предоставить [`repr()`](https://python-all.ru/3.7/library/functions.html#repr), который также скрывает (неважное) значение:719720```python721>>> class NoValue(Enum):722... def __repr__(self):723... return '<%s.%s>' % (self.__class__.__name__, self.name)724...725```726727#### Использование [`auto`](https://python-all.ru/3.7/library/enum.html#enum.auto)728729Использование [`auto`](https://python-all.ru/3.7/library/enum.html#enum.auto) будет выглядеть так:730731```python732>>> class Color(NoValue):733... RED = auto()734... BLUE = auto()735... GREEN = auto()736...737>>> Color.GREEN738<Color.GREEN>739```740741#### Использование [`object`](https://python-all.ru/3.7/library/functions.html#object)742743Использование [`object`](https://python-all.ru/3.7/library/functions.html#object) будет выглядеть так:744745```python746>>> class Color(NoValue):747... RED = object()748... GREEN = object()749... BLUE = object()750...751>>> Color.GREEN752<Color.GREEN>753```754755#### Использование описательной строки756757Использование строки в качестве значения будет выглядеть так:758759```python760>>> class Color(NoValue):761... RED = 'stop'762... GREEN = 'go'763... BLUE = 'too fast!'764...765>>> Color.GREEN766<Color.GREEN>767>>> Color.GREEN.value768'go'769```770771#### Использование собственного [`__new__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__new__)772773Использование автонумерующего [`__new__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__new__) будет выглядеть так:774775```python776>>> class AutoNumber(NoValue):777... def __new__(cls):778... value = len(cls.__members__) + 1779... obj = object.__new__(cls)780... obj._value_ = value781... return obj782...783>>> class Color(AutoNumber):784... RED = ()785... GREEN = ()786... BLUE = ()787...788>>> Color.GREEN789<Color.GREEN>790>>> Color.GREEN.value7912792```793794> **Примечание**795>796> Метод [`__new__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__new__), если он определён, используется во время создания членов Enum; затем он заменяется методом [`__new__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__new__) класса Enum, который используется после создания класса для поиска существующих членов.797798### OrderedEnum799800Упорядоченное перечисление, которое не основано на [`IntEnum`](https://python-all.ru/3.7/library/enum.html#enum.IntEnum) и поэтому сохраняет обычные инварианты [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) (например, несравнимость с другими перечислениями):801802```python803>>> class OrderedEnum(Enum):804... def __ge__(self, other):805... if self.__class__ is other.__class__:806... return self.value >= other.value807... return NotImplemented808... def __gt__(self, other):809... if self.__class__ is other.__class__:810... return self.value > other.value811... return NotImplemented812... def __le__(self, other):813... if self.__class__ is other.__class__:814... return self.value <= other.value815... return NotImplemented816... def __lt__(self, other):817... if self.__class__ is other.__class__:818... return self.value < other.value819... return NotImplemented820...821>>> class Grade(OrderedEnum):822... A = 5823... B = 4824... C = 3825... D = 2826... F = 1827...828>>> Grade.C < Grade.A829True830```831832### DuplicateFreeEnum833834Вызывает ошибку, если обнаружено дублирующееся имя члена, вместо создания псевдонима:835836```python837>>> class DuplicateFreeEnum(Enum):838... def __init__(self, *args):839... cls = self.__class__840... if any(self.value == e.value for e in cls):841... a = self.name842... e = cls(self.value).name843... raise ValueError(844... "aliases not allowed in DuplicateFreeEnum: %r --> %r"845... % (a, e))846...847>>> class Color(DuplicateFreeEnum):848... RED = 1849... GREEN = 2850... BLUE = 3851... GRENE = 2852...853Traceback (most recent call last):854...855ValueError: aliases not allowed in DuplicateFreeEnum: 'GRENE' --> 'GREEN'856```857858> **Примечание**859>860> Это полезный пример подкласса Enum для добавления или изменения другого поведения, а также запрета псевдонимов. Если требуется только запрет псевдонимов, вместо этого можно использовать декоратор [`unique()`](https://python-all.ru/3.7/library/enum.html#enum.unique).861862### Planet863864Если определены [`__new__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__new__) или [`__init__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__init__), значение члена перечисления будет передано этим методам:865866```python867>>> class Planet(Enum):868... MERCURY = (3.303e+23, 2.4397e6)869... VENUS = (4.869e+24, 6.0518e6)870... EARTH = (5.976e+24, 6.37814e6)871... MARS = (6.421e+23, 3.3972e6)872... JUPITER = (1.9e+27, 7.1492e7)873... SATURN = (5.688e+26, 6.0268e7)874... URANUS = (8.686e+25, 2.5559e7)875... NEPTUNE = (1.024e+26, 2.4746e7)876... def __init__(self, mass, radius):877... self.mass = mass # в килограммах878... self.radius = radius # в метрах879... @property880... def surface_gravity(self):881... # гравитационная постоянная (м3 кг-1 с-2)882... G = 6.67300E-11883... return G * self.mass / (self.radius * self.radius)884...885>>> Planet.EARTH.value886(5.976e+24, 6378140.0)887>>> Planet.EARTH.surface_gravity8889.802652743337129889```890891### TimePeriod892893Пример использования атрибута `_ignore_`:894895```python896>>> from datetime import timedelta897>>> class Period(timedelta, Enum):898... "different lengths of time"899... _ignore_ = 'Period i'900... Period = vars()901... for i in range(367):902... Period['day_%d' % i] = i903...904>>> list(Period)[:2]905[<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]906>>> list(Period)[-2:]907[<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]908```909910## Чем перечисления отличаются?911912Перечисления имеют собственный метакласс, который влияет на многие аспекты как производных классов Enum, так и их экземпляров (членов).913914### Классы Enum915916Метакласс `EnumMeta` отвечает за предоставление методов [`__contains__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__contains__), [`__dir__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__dir__), [`__iter__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__iter__) и других, которые позволяют выполнять с классом [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) действия, невозможные для обычного класса, например *list(Color)* или *some\_enum\_var in Color*. `EnumMeta` отвечает за то, чтобы различные другие методы конечного класса [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) были корректны (такие как [`__new__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__new__), [`__getnewargs__()`](https://python-all.ru/3.7/library/pickle.html#object.__getnewargs__), [`__str__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__str__) и [`__repr__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__repr__)).917918### Элементы Enum (также известные как экземпляры)919920Самое интересное в членах Enum – это то, что они являются синглтонами. `EnumMeta` создаёт их все при создании самого класса [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum), а затем помещает на место настраиваемый [`__new__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__new__), чтобы гарантировать, что новые экземпляры никогда не будут созданы, возвращая только существующие экземпляры членов.921922### Тонкие моменты923924#### Поддерживаемые `__dunder__` имена925926`__members__` – это `OrderedDict` из `member_name`:`member` элементов. Он доступен только у класса.927928[`__new__()`](https://python-all.ru/3.7/reference/datamodel.html#object.__new__), если указан, должен создавать и возвращать элементы перечисления; также рекомендуется соответствующим образом установить `_value_` элемента. После создания всех элементов он больше не используется.929930#### Поддерживаемые `_sunder_` имена931932- `_name_` – имя члена933- `_value_` – значение элемента; может быть установлено / изменено в `__new__`934- `_missing_` – функция поиска, используемая, когда значение не найдено; может быть переопределена935- `_ignore_` – список имён, либо в виде [`list()`](https://python-all.ru/3.7/library/stdtypes.html#list), либо [`str()`](https://python-all.ru/3.7/library/stdtypes.html#str), которые не будут преобразованы в элементы и будут удалены из итогового класса936- `_order_` – используется в коде для Python 2/3 для обеспечения согласованности порядка элементов (атрибут класса, удаляется при создании класса)937- `_generate_next_value_` – используется [функциональным API](https://python-all.ru/3.7/library/enum.html#functional-api) и [`auto`](https://python-all.ru/3.7/library/enum.html#enum.auto) для получения подходящего значения для элемента перечисления; может быть переопределён938939Новое в версии 3.6: `_missing_`, `_order_`, `_generate_next_value_`940941Новое в версии 3.7: `_ignore_`942943Чтобы помочь синхронизировать код Python 2 и Python 3, можно указать атрибут `_order_`. Он будет проверен на соответствие фактическому порядку перечисления, и если они не совпадают, будет вызвана ошибка:944945```python946>>> class Color(Enum):947... _order_ = 'RED GREEN BLUE'948... RED = 1949... BLUE = 3950... GREEN = 2951...952Traceback (most recent call last):953...954TypeError: member order does not match _order_955```956957> **Примечание**958>959> В коде Python 2 атрибут `_order_` необходим, поскольку порядок определения теряется до того, как его можно зафиксировать.960961#### Тип члена `Enum`962963Члены [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) являются экземплярами своего класса [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) и обычно доступны как `EnumClass.member`. При определённых обстоятельствах к ним также можно обращаться как `EnumClass.member.member`, но никогда не следует этого делать, так как такой поиск может завершиться неудачей или, что ещё хуже, вернуть что-то кроме искомого члена [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) (это ещё одна веская причина использовать для членов имена в верхнем регистре):964965```python966>>> class FieldTypes(Enum):967... name = 0968... value = 1969... size = 2970...971>>> FieldTypes.value.size972<FieldTypes.size: 2>973>>> FieldTypes.size.value9742975```976977Изменено в версии 3.5.978979#### Логическое значение классов и членов `Enum`980981Члены [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum), смешанные с не-[`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) типами (такими как [`int`](https://python-all.ru/3.7/library/functions.html#int), [`str`](https://python-all.ru/3.7/library/stdtypes.html#str) и т.п.), вычисляются по правилам примешанного типа; в противном случае все члены вычисляются как [`True`](https://python-all.ru/3.7/library/constants.html#True). Чтобы логическое вычисление вашего собственного Enum зависело от значения члена, добавьте в свой класс следующее:982983```python984def __bool__(self):985 return bool(self.value)986```987988Классы [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) всегда вычисляются как [`True`](https://python-all.ru/3.7/library/constants.html#True).989990#### `Enum` классы с методами991992Если добавить подклассу [`Enum`](https://python-all.ru/3.7/library/enum.html#enum.Enum) дополнительные методы, как в классе [Planet](https://python-all.ru/3.7/library/enum.html#planet) выше, эти методы будут видны в [`dir()`](https://python-all.ru/3.7/library/functions.html#dir) члена, но не класса:993994```python995>>> dir(Planet)996['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__members__', '__module__']997>>> dir(Planet.EARTH)998['__class__', '__doc__', '__module__', 'name', 'surface_gravity', 'value']999```10001001#### Объединение элементов `Flag`10021003Если комбинация членов Flag не имеет имени, [`repr()`](https://python-all.ru/3.7/library/functions.html#repr) будет включать все именованные флаги и все именованные комбинации флагов, присутствующие в значении:10041005```python1006>>> class Color(Flag):1007... RED = auto()1008... GREEN = auto()1009... BLUE = auto()1010... MAGENTA = RED | BLUE1011... YELLOW = RED | GREEN1012... CYAN = GREEN | BLUE1013...1014>>> Color(3) # именованная комбинация1015<Color.YELLOW: 3>1016>>> Color(7) # не именованная комбинация1017<Color.CYAN|MAGENTA|BLUE|YELLOW|GREEN|RED: 7>1018```1019