Документация Python неофициальный перевод

enum.md

1342 строк · 67.7 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.11/howto/enum.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# HOWTO по перечислениям89Перечисление [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) – это набор символьных имён, привязанных к уникальным значениям. Они похожи на глобальные переменные, но предоставляют более полезные [`repr()`](https://python-all.ru/3.11/library/functions.html#repr), группировку, типобезопасность и некоторые другие возможности.1011Они наиболее полезны, когда у вас есть переменная, которая может принимать одно из ограниченного набора значений. Например, дни недели:1213```python14>>> from enum import Enum15>>> class Weekday(Enum):16...     MONDAY = 117...     TUESDAY = 218...     WEDNESDAY = 319...     THURSDAY = 420...     FRIDAY = 521...     SATURDAY = 622...     SUNDAY = 723```2425Или, возможно, основные цвета RGB:2627```python28>>> from enum import Enum29>>> class Color(Enum):30...     RED = 131...     GREEN = 232...     BLUE = 333```3435Как видите, создать [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) так же просто, как написать класс, наследующий от самого [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum).3637> **Примечание**38>39> Регистр имён членов перечисления40>41> Поскольку перечисления используются для представления констант, рекомендуется использовать имена членов в ВЕРХНЕМ\_РЕГИСТРЕ, и в примерах мы будем придерживаться этого стиля.4243В зависимости от природы перечисления значение члена может быть важным или нет, но в любом случае это значение можно использовать для получения соответствующего члена:4445```python46>>> Weekday(3)47<Weekday.WEDNESDAY: 3>48```4950Как видите, `repr()` члена показывает имя перечисления, имя члена и значение. `str()` члена показывает только имя перечисления и имя члена:5152```python53>>> print(Weekday.THURSDAY)54Weekday.THURSDAY55```5657*Тип* члена перечисления – это перечисление, которому он принадлежит:5859```python60>>> type(Weekday.MONDAY)61<enum 'Weekday'>62>>> isinstance(Weekday.FRIDAY, Weekday)63True64```6566У членов перечисления есть атрибут, содержащий только их `name`:6768```python69>>> print(Weekday.TUESDAY.name)70TUESDAY71```7273Аналогично, у них есть атрибут для их `value`:7475```python76>>> Weekday.WEDNESDAY.value77378```7980В отличие от многих языков, где перечисления рассматриваются исключительно как пары имя/значение, в Python перечисления могут иметь поведение. Например, [`datetime.date`](https://python-all.ru/3.11/library/datetime.html#datetime.date) содержит два метода для возврата дня недели: `weekday()` и `isoweekday()`. Разница в том, что один считает от 0 до 6, а другой – от 1 до 7. Вместо того чтобы запоминать это, можно добавить метод в перечисление `Weekday` , который будет извлекать день из экземпляра `date` и возвращать соответствующий элемент перечисления:8182```python83@classmethod84def from_date(cls, date):85    return cls(date.isoweekday())86```8788Полное перечисление `Weekday` теперь выглядит так:8990```python91>>> class Weekday(Enum):92...     MONDAY = 193...     TUESDAY = 294...     WEDNESDAY = 395...     THURSDAY = 496...     FRIDAY = 597...     SATURDAY = 698...     SUNDAY = 799...     #100...     @classmethod101...     def from_date(cls, date):102...         return cls(date.isoweekday())103```104105Теперь мы можем узнать, какой сегодня день! Смотрите:106107```python108>>> from datetime import date109>>> Weekday.from_date(date.today())     110<Weekday.TUESDAY: 2>111```112113Конечно, если вы читаете это в другой день, вы увидите этот день вместо.114115Это перечисление `Weekday` отлично подходит, если нашей переменной нужен только один день, но что если нужно несколько? Возможно, мы пишем функцию для планирования дел на неделю и не хотим использовать [`list`](https://python-all.ru/3.11/library/stdtypes.html#list) – мы могли бы использовать другой тип [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum):116117```python118>>> from enum import Flag119>>> class Weekday(Flag):120...     MONDAY = 1121...     TUESDAY = 2122...     WEDNESDAY = 4123...     THURSDAY = 8124...     FRIDAY = 16125...     SATURDAY = 32126...     SUNDAY = 64127```128129Мы изменили две вещи: мы наследуем от [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag), и все значения являются степенями двойки.130131Так же, как и в исходном перечислении `Weekday` выше, мы можем иметь одиночный выбор:132133```python134>>> first_week_day = Weekday.MONDAY135>>> first_week_day136<Weekday.MONDAY: 1>137```138139Но [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag) также позволяет нам объединить несколько членов в одну переменную:140141```python142>>> weekend = Weekday.SATURDAY | Weekday.SUNDAY143>>> weekend144<Weekday.SATURDAY|SUNDAY: 96>145```146147Можно даже перебирать переменную [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag):148149```python150>>> for day in weekend:151...     print(day)152Weekday.SATURDAY153Weekday.SUNDAY154```155156Итак, давайте настроим несколько задач:157158```python159>>> chores_for_ethan = {160...     'feed the cat': Weekday.MONDAY | Weekday.WEDNESDAY | Weekday.FRIDAY,161...     'do the dishes': Weekday.TUESDAY | Weekday.THURSDAY,162...     'answer SO questions': Weekday.SATURDAY,163...     }164```165166И функция для отображения задач на заданный день:167168```python169>>> def show_chores(chores, day):170...     for chore, days in chores.items():171...         if day in days:172...             print(chore)173>>> show_chores(chores_for_ethan, Weekday.SATURDAY)174answer SO questions175```176177В случаях, когда фактические значения членов не важны, можно сэкономить время и использовать [`auto()`](https://python-all.ru/3.11/library/enum.html#enum.auto) для значений:178179```python180>>> from enum import auto181>>> class Weekday(Flag):182...     MONDAY = auto()183...     TUESDAY = auto()184...     WEDNESDAY = auto()185...     THURSDAY = auto()186...     FRIDAY = auto()187...     SATURDAY = auto()188...     SUNDAY = auto()189...     WEEKEND = SATURDAY | SUNDAY190```191192## Программный доступ к членам перечисления и их атрибутам193194Иногда бывает полезно обращаться к членам перечисления программно (например, в ситуациях, когда `Color.RED` не подходит, поскольку точный цвет неизвестен на момент написания программы). `Enum` предоставляет такой доступ:195196```python197>>> Color(1)198<Color.RED: 1>199>>> Color(3)200<Color.BLUE: 3>201```202203Если требуется обратиться к членам перечисления по *имени*, используйте доступ по ключу:204205```python206>>> Color['RED']207<Color.RED: 1>208>>> Color['GREEN']209<Color.GREEN: 2>210```211212Если есть член перечисления и требуется его `name` или `value`:213214```python215>>> member = Color.RED216>>> member.name217'RED'218>>> member.value2191220```221222## Дублирование членов и значений перечисления223224Наличие двух членов перечисления с одинаковым именем недопустимо:225226```python227>>> class Shape(Enum):228...     SQUARE = 2229...     SQUARE = 3230...231Traceback (most recent call last):232...233TypeError: 'SQUARE' already defined as 2234```235236Однако член перечисления может иметь и другие связанные с ним имена. Если имеются две записи `A` и `B` с одинаковым значением (и `A` определён первой), то `B` является псевдонимом для члена `A`. Поиск по значению значения `A` вернёт член `A`. Поиск по имени `A` вернёт член `A`. Поиск по имени `B` также вернёт член `A`:237238```python239>>> class Shape(Enum):240...     SQUARE = 2241...     DIAMOND = 1242...     CIRCLE = 3243...     ALIAS_FOR_SQUARE = 2244...245>>> Shape.SQUARE246<Shape.SQUARE: 2>247>>> Shape.ALIAS_FOR_SQUARE248<Shape.SQUARE: 2>249>>> Shape(2)250<Shape.SQUARE: 2>251```252253> **Примечание**254>255> Попытка создать член с тем же именем, что и уже определённый атрибут (другой член, метод и т.д.), или попытка создать атрибут с тем же именем, что и член, не допускается.256257## Обеспечение уникальности значений перечисления258259По умолчанию перечисления допускают несколько имён в качестве псевдонимов одного и того же значения. Если такое поведение нежелательно, можно использовать декоратор [`unique()`](https://python-all.ru/3.11/library/enum.html#enum.unique):260261```python262>>> from enum import Enum, unique263>>> @unique264... class Mistake(Enum):265...     ONE = 1266...     TWO = 2267...     THREE = 3268...     FOUR = 3269...270Traceback (most recent call last):271...272ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE273```274275## Использование автоматических значений276277Если точное значение неважно, можно использовать [`auto`](https://python-all.ru/3.11/library/enum.html#enum.auto):278279```python280>>> from enum import Enum, auto281>>> class Color(Enum):282...     RED = auto()283...     BLUE = auto()284...     GREEN = auto()285...286>>> [member.value for member in Color]287[1, 2, 3]288```289290Значения выбираются с помощью `_generate_next_value_()`, который можно переопределить:291292```python293>>> class AutoName(Enum):294...     def _generate_next_value_(name, start, count, last_values):295...         return name296...297>>> class Ordinal(AutoName):298...     NORTH = auto()299...     SOUTH = auto()300...     EAST = auto()301...     WEST = auto()302...303>>> [member.value for member in Ordinal]304['NORTH', 'SOUTH', 'EAST', 'WEST']305```306307> **Примечание**308>309> Метод `_generate_next_value_()` должен быть определён до любых членов.310311## Перебор312313Перебор членов перечисления не включает псевдонимы:314315```python316>>> list(Shape)317[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]318>>> list(Weekday)319[<Weekday.MONDAY: 1>, <Weekday.TUESDAY: 2>, <Weekday.WEDNESDAY: 4>, <Weekday.THURSDAY: 8>, <Weekday.FRIDAY: 16>, <Weekday.SATURDAY: 32>, <Weekday.SUNDAY: 64>]320```321322Обратите внимание, что псевдонимы `Shape.ALIAS_FOR_SQUARE` и `Weekday.WEEKEND` не отображаются.323324Специальный атрибут `__members__` – это упорядоченное отображение имён на члены, доступное только для чтения. Он включает все имена, определённые в перечислении, включая псевдонимы:325326```python327>>> for name, member in Shape.__members__.items():328...     name, member329...330('SQUARE', <Shape.SQUARE: 2>)331('DIAMOND', <Shape.DIAMOND: 1>)332('CIRCLE', <Shape.CIRCLE: 3>)333('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)334```335336Атрибут `__members__` можно использовать для детального программного доступа к членам перечисления. Например, для поиска всех псевдонимов:337338```python339>>> [name for name, member in Shape.__members__.items() if member.name != name]340['ALIAS_FOR_SQUARE']341```342343> **Примечание**344>345> Псевдонимы для флагов включают значения с несколькими установленными флагами, например `3`, и без установленных флагов, т.е. `0`.346347## Сравнения348349Члены перечисления сравниваются по идентичности:350351```python352>>> Color.RED is Color.RED353True354>>> Color.RED is Color.BLUE355False356>>> Color.RED is not Color.BLUE357True358```359360Упорядоченные сравнения между значениями перечисления *не* поддерживаются. Члены перечисления – не целые числа (но см. [IntEnum](https://python-all.ru/3.11/howto/enum.html#intenum) ниже):361362```python363>>> Color.RED < Color.BLUE364Traceback (most recent call last):365  File "<stdin>", line 1, in <module>366TypeError: '<' not supported between instances of 'Color' and 'Color'367```368369Однако сравнения на равенство определены:370371```python372>>> Color.BLUE == Color.RED373False374>>> Color.BLUE != Color.RED375True376>>> Color.BLUE == Color.BLUE377True378```379380Сравнения со значениями, не являющимися перечислениями, всегда дают результат «не равно» (опять же, [`IntEnum`](https://python-all.ru/3.11/library/enum.html#enum.IntEnum) был явно спроектирован для другого поведения, см. ниже):381382```python383>>> Color.BLUE == 2384False385```386387> **Предупреждение**388>389> Можно перезагружать модули – если перезагруженный модуль содержит перечисления, они будут воссозданы, и новые члены могут не совпадать (по идентичности или равенству) с исходными членами.390391## Допустимые члены и атрибуты перечислений392393Большинство примеров выше используют целые числа для значений перечисления. Использование целых чисел кратко и удобно (и предоставляется по умолчанию [функциональным API](https://python-all.ru/3.11/howto/enum.html#functional-api)), но не является строго обязательным. В подавляющем большинстве случаев неважно, каково фактическое значение перечисления. Но если значение *важно*, перечисления могут иметь произвольные значения.394395Перечисления – это классы Python и могут иметь обычные методы и специальные методы. Если есть такое перечисление:396397```python398>>> class Mood(Enum):399...     FUNKY = 1400...     HAPPY = 3401...402...     def describe(self):403...         # self – это член перечисления404...         return self.name, self.value405...406...     def __str__(self):407...         return 'my custom str! {0}'.format(self.value)408...409...     @classmethod410...     def favorite_mood(cls):411...         # cls здесь – это перечисление412...         return cls.HAPPY413...414```415416Тогда:417418```python419>>> Mood.favorite_mood()420<Mood.HAPPY: 3>421>>> Mood.HAPPY.describe()422('HAPPY', 3)423>>> str(Mood.FUNKY)424'my custom str! 1'425```426427Правила допустимого таковы: имена, которые начинаются и заканчиваются одним подчёркиванием, зарезервированы для enum и не могут использоваться; все остальные атрибуты, определённые внутри перечисления, становятся его членами, за исключением специальных методов (`__str__()`, `__add__()` и т.д.), дескрипторов (методы тоже являются дескрипторами) и имён переменных, перечисленных в `_ignore_`.428429Примечание: если перечисление определяет `__new__()` и/или `__init__()`, любые значения, переданные члену перечисления, будут переданы в эти методы. Пример см. в [Planet](https://python-all.ru/3.11/howto/enum.html#planet).430431> **Примечание**432>433> Метод `__new__()`, если определён, используется при создании членов Enum; затем он заменяется методом `__new__()` Enum, который используется после создания класса для поиска существующих членов. Подробнее см. [Когда использовать \_\_new\_\_() vs. \_\_init\_\_()](https://python-all.ru/3.11/howto/enum.html#new-vs-init).434435## Ограниченное создание подклассов Enum436437Новый класс [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) должен иметь один базовый класс перечисления, не более одного конкретного типа данных и столько миксин-классов на основе [`object`](https://python-all.ru/3.11/library/functions.html#object), сколько нужно. Порядок этих базовых классов:438439```python440class EnumName([mix-in, ...,] [data-type,] base-enum):441    pass442```443444Также создание подкласса перечисления разрешено только в том случае, если перечисление не определяет никаких членов. Поэтому это запрещено:445446```python447>>> class MoreColor(Color):448...     PINK = 17449...450Traceback (most recent call last):451...452TypeError: <enum 'MoreColor'> cannot extend <enum 'Color'>453```454455Но это разрешено:456457```python458>>> class Foo(Enum):459...     def some_behavior(self):460...         pass461...462>>> class Bar(Foo):463...     HAPPY = 1464...     SAD = 2465...466```467468Разрешение создания подклассов перечислений, определяющих члены, привело бы к нарушению некоторых важных инвариантов типов и экземпляров. С другой стороны, имеет смысл разрешить общее поведение для группы перечислений. (Пример см. в [OrderedEnum](https://python-all.ru/3.11/howto/enum.html#orderedenum).)469470## Пиклинг471472Перечисления могут быть упакованы и распакованы с помощью модуля pickle.473474```python475>>> from test.test_enum import Fruit476>>> from pickle import dumps, loads477>>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))478True479```480481Обычные ограничения для упаковки с помощью модуля pickle применяются: перечисления, которые можно упаковать, должны быть определены на верхнем уровне модуля, так как для распаковки их нужно импортировать из этого модуля.482483> **Примечание**484>485> С протоколом pickle версии 4 можно легко упаковывать перечисления, вложенные в другие классы.486487Можно изменить способ упаковки/распаковки членов перечисления, определив `__reduce_ex__()` в классе перечисления. Метод по умолчанию – по значению (by-value), но перечисления со сложными значениями могут захотеть использовать по имени (by-name):488489```python490>>> import enum491>>> class MyEnum(enum.Enum):492...     __reduce_ex__ = enum.pickle_by_enum_name493```494495> **Примечание**496>497> Использование по имени для флагов не рекомендуется, так как безымянные псевдонимы не будут распаковываться.498499## Функциональное API500501Класс [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) является вызываемым и предоставляет следующее функциональное API:502503```python504>>> Animal = Enum('Animal', 'ANT BEE CAT DOG')505>>> Animal506<enum 'Animal'>507>>> Animal.ANT508<Animal.ANT: 1>509>>> list(Animal)510[<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]511```512513Семантика этого API напоминает [`namedtuple`](https://python-all.ru/3.11/library/collections.html#collections.namedtuple). Первый аргумент вызова [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) – это имя перечисления.514515Второй аргумент – это *источник* имён членов перечисления. Это может быть строка имён, разделённых пробелами, последовательность имён, последовательность двухэлементных кортежей с парами ключ/значение или отображение (например, словарь) имён на значения. Последние два варианта позволяют присваивать произвольные значения перечислениям; остальные автоматически присваивают увеличивающиеся целые числа, начиная с 1 (используйте параметр `start` для указания другого начального значения). Возвращается новый класс, производный от [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum). Другими словами, приведённое выше присваивание `Animal` эквивалентно:516517```python518>>> class Animal(Enum):519...     ANT = 1520...     BEE = 2521...     CAT = 3522...     DOG = 4523...524```525526Причина выбора `1` в качестве начального числа, а не `0`, заключается в том, что `0` является `False` в логическом смысле, но по умолчанию все члены перечисления вычисляются как `True`.527528Pickling перечислений, созданных с помощью функционального API, может быть сложным, так как используются детали реализации стека фреймов для определения модуля, в котором создаётся перечисление (например, это не сработает, если используется вспомогательная функция в отдельном модуле, и может не работать на IronPython или Jython). Решение – явно указать имя модуля следующим образом:529530```python531>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)532```533534> **Предупреждение**535>536> Если `module` не указан, и Enum не может его определить, новые члены Enum не будут поддерживать распаковку; чтобы ошибки были ближе к источнику, pickling будет отключён.537538Новый протокол pickle 4 также в некоторых обстоятельствах полагается на то, что [`__qualname__`](https://python-all.ru/3.11/library/stdtypes.html#definition.__qualname__) установлен в расположение, где pickle сможет найти класс. Например, если класс стал доступен в классе SomeData в глобальной области видимости:539540```python541>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')542```543544Полная сигнатура:545546```python547Enum(548    value='NewEnumName',549    names=<...>,550    *,551    module='...',552    qualname='...',553    type=<mixed-in class>,554    start=1,555    )556```557558- *value*: Что новый класс перечисления будет записывать в качестве своего имени.559- *names*: Члены перечисления. Это может быть строка, разделённая пробелами или запятыми (значения будут начинаться с 1, если не указано иное):560561  ```python562  'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'563  ```564565  или итератор имён:566567  ```python568  ['RED', 'GREEN', 'BLUE']569  ```570571  или итератор пар (имя, значение):572573  ```python574  [('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]575  ```576577  или отображение:578579  ```python580  {'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}581  ```582- *module*: имя модуля, в котором можно найти новый класс перечисления.583- *qualname*: положение нового класса перечисления в модуле.584- *type*: тип, подмешиваемый к новому классу перечисления.585- *start*: число, с которого начинать отсчёт, если переданы только имена.586587Изменено в версии 3.5: Добавлен параметр *start*.588589## Производные перечисления590591### IntEnum592593Первая разновидность [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) также является подклассом [`int`](https://python-all.ru/3.11/library/functions.html#int). Элементы [`IntEnum`](https://python-all.ru/3.11/library/enum.html#enum.IntEnum) можно сравнивать с целыми числами; соответственно, целочисленные перечисления разных типов также можно сравнивать друг с другом:594595```python596>>> from enum import IntEnum597>>> class Shape(IntEnum):598...     CIRCLE = 1599...     SQUARE = 2600...601>>> class Request(IntEnum):602...     POST = 1603...     GET = 2604...605>>> Shape == 1606False607>>> Shape.CIRCLE == 1608True609>>> Shape.CIRCLE == Request.POST610True611```612613Однако их по-прежнему нельзя сравнивать со стандартными перечислениями [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum):614615```python616>>> class Shape(IntEnum):617...     CIRCLE = 1618...     SQUARE = 2619...620>>> class Color(Enum):621...     RED = 1622...     GREEN = 2623...624>>> Shape.CIRCLE == Color.RED625False626```627628Значения [`IntEnum`](https://python-all.ru/3.11/library/enum.html#enum.IntEnum) ведут себя как целые числа и в других ожидаемых аспектах:629630```python631>>> int(Shape.CIRCLE)6321633>>> ['a', 'b', 'c'][Shape.CIRCLE]634'b'635>>> [i for i in range(Shape.SQUARE)]636[0, 1]637```638639### StrEnum640641Вторая разновидность [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) также является подклассом [`str`](https://python-all.ru/3.11/library/stdtypes.html#str). Элементы [`StrEnum`](https://python-all.ru/3.11/library/enum.html#enum.StrEnum) можно сравнивать со строками; соответственно, строковые перечисления разных типов также можно сравнивать друг с другом.642643Новое в версии 3.11.644645### IntFlag646647Следующая разновидность [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) – [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag) – также основана на [`int`](https://python-all.ru/3.11/library/functions.html#int). Отличие в том, что элементы [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag) можно комбинировать с помощью побитовых операторов (&, |, ^, ~), и результат, по возможности, остаётся элементом [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag). Как и [`IntEnum`](https://python-all.ru/3.11/library/enum.html#enum.IntEnum), элементы [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag) также являются целыми числами и могут использоваться везде, где используется [`int`](https://python-all.ru/3.11/library/functions.html#int).648649> **Примечание**650>651> Любая операция с элементом [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag), кроме побитовых, приведёт к потере принадлежности к [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag).652>653> Побитовые операции, результатом которых являются недопустимые значения [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag), приводят к потере принадлежности к [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag). Подробнее см. [`FlagBoundary`](https://python-all.ru/3.11/library/enum.html#enum.FlagBoundary).654655Новое в версии 3.6.656657Изменено в версии 3.11.658659Пример класса [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag):660661```python662>>> from enum import IntFlag663>>> class Perm(IntFlag):664...     R = 4665...     W = 2666...     X = 1667...668>>> Perm.R | Perm.W669<Perm.R|W: 6>670>>> Perm.R + Perm.W6716672>>> RW = Perm.R | Perm.W673>>> Perm.R in RW674True675```676677Также можно давать имена комбинациям:678679```python680>>> class Perm(IntFlag):681...     R = 4682...     W = 2683...     X = 1684...     RWX = 7685>>> Perm.RWX686<Perm.RWX: 7>687>>> ~Perm.RWX688<Perm: 0>689>>> Perm(7)690<Perm.RWX: 7>691```692693> **Примечание**694>695> Именованные комбинации считаются псевдонимами. Псевдонимы не отображаются при итерации, но могут быть возвращены при поиске по значению.696697Изменено в версии 3.11.698699Ещё одно важное отличие между [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag) и [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) в том, что если ни один флаг не установлен (значение равно 0), то его логическое значение – [`False`](https://python-all.ru/3.11/library/constants.html#False):700701```python702>>> Perm.R & Perm.X703<Perm: 0>704>>> bool(Perm.R & Perm.X)705False706```707708Поскольку элементы [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag) также являются подклассами [`int`](https://python-all.ru/3.11/library/functions.html#int), их можно комбинировать с ними (но при этом может быть потеряна принадлежность к [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag):709710```python711>>> Perm.X | 4712<Perm.R|X: 5>713714>>> Perm.X + 87159716```717718> **Примечание**719>720> Оператор отрицания `~` всегда возвращает элемент [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag) с положительным значением:721>722> ```python723> >>> (~Perm.X).value == (Perm.R|Perm.W).value == 6724> True725> ```726727Члены [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag) также можно перебирать:728729```python730>>> list(RW)731[<Perm.R: 4>, <Perm.W: 2>]732```733734Новое в версии 3.11.735736### Flag737738Последняя разновидность – [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag). Как и [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag), элементы [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag) можно комбинировать с помощью побитовых операторов (&, |, ^, ~). В отличие от [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag), их нельзя комбинировать или сравнивать ни с каким другим перечислением [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag), а также с [`int`](https://python-all.ru/3.11/library/functions.html#int). Хотя можно задавать значения напрямую, рекомендуется использовать [`auto`](https://python-all.ru/3.11/library/enum.html#enum.auto) в качестве значения и позволить [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag) выбрать подходящее значение.739740Новое в версии 3.6.741742Как и в случае с [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag), если комбинация элементов [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag) не содержит установленных флагов, логическое значение равно [`False`](https://python-all.ru/3.11/library/constants.html#False):743744```python745>>> from enum import Flag, auto746>>> class Color(Flag):747...     RED = auto()748...     BLUE = auto()749...     GREEN = auto()750...751>>> Color.RED & Color.GREEN752<Color: 0>753>>> bool(Color.RED & Color.GREEN)754False755```756757Отдельные флаги должны иметь значения, являющиеся степенями двойки (1, 2, 4, 8, …), а комбинации флагов – нет:758759```python760>>> class Color(Flag):761...     RED = auto()762...     BLUE = auto()763...     GREEN = auto()764...     WHITE = RED | BLUE | GREEN765...766>>> Color.WHITE767<Color.WHITE: 7>768```769770Присвоение имени условию «флаги не установлены» не меняет его логическое значение:771772```python773>>> class Color(Flag):774...     BLACK = 0775...     RED = auto()776...     BLUE = auto()777...     GREEN = auto()778...779>>> Color.BLACK780<Color.BLACK: 0>781>>> bool(Color.BLACK)782False783```784785Члены [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag) также можно перебирать:786787```python788>>> purple = Color.RED | Color.BLUE789>>> list(purple)790[<Color.RED: 1>, <Color.BLUE: 2>]791```792793Новое в версии 3.11.794795> **Примечание**796>797> Для большинства нового кода настоятельно рекомендуются [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) и [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag), поскольку [`IntEnum`](https://python-all.ru/3.11/library/enum.html#enum.IntEnum) и [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag) нарушают некоторые семантические обещания перечисления (будучи сравнимыми с целыми числами, а значит, по транзитивности, и с другими не связанными перечислениями). [`IntEnum`](https://python-all.ru/3.11/library/enum.html#enum.IntEnum) и [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag) следует использовать только в тех случаях, когда [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) и [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag) не подходят; например, при замене целочисленных констант на перечисления или для взаимодействия с другими системами.798799### Другие800801Хотя [`IntEnum`](https://python-all.ru/3.11/library/enum.html#enum.IntEnum) является частью модуля [`enum`](https://python-all.ru/3.11/library/enum.html#module-enum), его очень просто реализовать самостоятельно:802803```python804class IntEnum(int, Enum):805    pass806```807808Это показывает, как можно определить подобные производные перечисления; например, `FloatEnum`, в который примешивается [`float`](https://python-all.ru/3.11/library/functions.html#float) вместо [`int`](https://python-all.ru/3.11/library/functions.html#int).809810Некоторые правила:8118121. При создании подкласса [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) типы-примеси должны располагаться перед самим [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) в последовательности базовых классов, как в [`IntEnum`](https://python-all.ru/3.11/library/enum.html#enum.IntEnum) примере выше.8132. Примешиваемые типы должны быть наследуемыми. Например, [`bool`](https://python-all.ru/3.11/library/functions.html#bool) и [`range`](https://python-all.ru/3.11/library/stdtypes.html#range) не являются наследуемыми и приведут к ошибке во время создания Enum, если используются в качестве примешиваемого типа.8143. Хотя [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) может содержать члены любого типа, после примешивания дополнительного типа все члены должны иметь значения этого типа, например [`int`](https://python-all.ru/3.11/library/functions.html#int) выше. Это ограничение не распространяется на примеси, которые только добавляют методы и не задают другой тип.8154. При примешивании другого типа данных атрибут `value` *отличается* от самого члена перечисления, хотя он эквивалентен и будет равным при сравнении.8165. `data type` – это примесь, определяющая `__new__()`.8176. Форматирование в стиле %: `%s` и `%r` вызывают `__str__()` и `__repr__()` класса [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) соответственно; другие коды (например, `%i` или `%h` для IntEnum) обрабатывают член перечисления как его примешанный тип.8187. [Форматированные строковые литералы](https://python-all.ru/3.11/reference/lexical_analysis.html#f-strings), [`str.format()`](https://python-all.ru/3.11/library/stdtypes.html#str.format) и [`format()`](https://python-all.ru/3.11/library/functions.html#format) будут использовать метод `__str__()` перечисления.819820> **Примечание**821>822> Поскольку [`IntEnum`](https://python-all.ru/3.11/library/enum.html#enum.IntEnum), [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag) и [`StrEnum`](https://python-all.ru/3.11/library/enum.html#enum.StrEnum) предназначены для замены существующих констант «на лету», их метод `__str__()` был переопределён на метод `__str__()` их типа данных.823824## Когда использовать `__new__()` или `__init__()`825826`__new__()` следует использовать всякий раз, когда требуется настроить фактическое значение члена [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum). Любые другие изменения можно вносить как в `__new__()`, так и в `__init__()`, при этом предпочтение отдаётся `__init__()`.827828Например, если требуется передать конструктору несколько элементов, но только один из них должен быть значением:829830```python831>>> class Coordinate(bytes, Enum):832...     """833...     Согласование с двоичными кодами, которые можно индексировать по целочисленному коду.834...     """835...     def __new__(cls, value, label, unit):836...         obj = bytes.__new__(cls, [value])837...         obj._value_ = value838...         obj.label = label839...         obj.unit = unit840...         return obj841...     PX = (0, 'P.X', 'km')842...     PY = (1, 'P.Y', 'km')843...     VX = (2, 'V.X', 'km/s')844...     VY = (3, 'V.Y', 'km/s')845...846847>>> print(Coordinate['PY'])848Coordinate.PY849850>>> print(Coordinate(3))851Coordinate.VY852```853854> **Предупреждение**855>856> *Не вызывайте* `super().__new__()`, поскольку будет найден `__new__`, предназначенный только для поиска; вместо этого используйте непосредственно тип данных.857858### Тонкие моменты859860#### Поддерживаемые `__dunder__` имена861862`__members__` представляет собой упорядоченное отображение только для чтения элементов `member_name`:`member`. Оно доступно только на уровне класса.863864`__new__()`, если указан, должен создавать и возвращать элементы перечисления; также рекомендуется соответствующим образом установить `_value_` элемента. После создания всех элементов он больше не используется.865866#### Поддерживаемые `_sunder_` имена867868- `_name_` – имя члена869- `_value_` – значение элемента; может быть установлено / изменено в `__new__`870- `_missing_` – функция поиска, используемая, когда значение не найдено; может быть переопределена871- `_ignore_` – список имён, либо в виде [`list`](https://python-all.ru/3.11/library/stdtypes.html#list), либо [`str`](https://python-all.ru/3.11/library/stdtypes.html#str), которые не будут преобразованы в элементы и будут удалены из итогового класса872- `_order_` – используется в коде для Python 2/3 для обеспечения согласованности порядка элементов (атрибут класса, удаляется при создании класса)873- `_generate_next_value_` – используется [функциональным API](https://python-all.ru/3.11/howto/enum.html#functional-api) и [`auto`](https://python-all.ru/3.11/library/enum.html#enum.auto) для получения подходящего значения для элемента перечисления; может быть переопределён874875> **Примечание**876>877> Для стандартных классов [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) следующее выбираемое значение равно последнему увиденному значению, увеличенному на единицу.878>879> Для классов [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag) следующее выбираемое значение будет следующей по величине степенью двойки, независимо от последнего увиденного значения.880881Новое в версии 3.6: `_missing_`, `_order_`, `_generate_next_value_`882883Новое в версии 3.7: `_ignore_`884885Чтобы помочь синхронизировать код Python 2 и Python 3, можно указать атрибут `_order_`. Он будет проверен на соответствие фактическому порядку перечисления, и если они не совпадают, будет вызвана ошибка:886887```python888>>> class Color(Enum):889...     _order_ = 'RED GREEN BLUE'890...     RED = 1891...     BLUE = 3892...     GREEN = 2893...894Traceback (most recent call last):895...896TypeError: member order does not match _order_:897  ['RED', 'BLUE', 'GREEN']898  ['RED', 'GREEN', 'BLUE']899```900901> **Примечание**902>903> В коде Python 2 атрибут `_order_` необходим, поскольку порядок определения теряется до того, как его можно зафиксировать.904905#### \_Private\_\_names906907[Приватные имена](https://python-all.ru/3.11/reference/expressions.html#private-name-mangling) не преобразуются в члены перечисления, а остаются обычными атрибутами.908909Изменено в версии 3.11.910911#### Тип члена `Enum`912913Члены перечисления являются экземплярами своего класса перечисления и обычно доступны как `EnumClass.member`. В некоторых случаях, например при написании пользовательского поведения перечисления, возможность прямого доступа к одному члену из другого бывает полезна и поддерживается.914915Изменено в версии 3.5.916917#### Создание членов, примешанных к другим типам данных918919При наследовании от других типов данных, таких как [`int`](https://python-all.ru/3.11/library/functions.html#int) или [`str`](https://python-all.ru/3.11/library/stdtypes.html#str), в сочетании с [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum), все значения после `=` передаются конструктору этого типа данных. Например:920921```python922>>> class MyEnum(IntEnum):      # help(int) -> int(x, base=10) -> integer923...     example = '11', 16      # итак, x='11' и base=16924...925>>> MyEnum.example.value        # и hex(11) – это...92617927```928929#### Логическое значение классов и членов `Enum`930931Классы перечислений, в которые примешаны не-[`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) типы (например, [`int`](https://python-all.ru/3.11/library/functions.html#int), [`str`](https://python-all.ru/3.11/library/stdtypes.html#str) и т.д.), вычисляются по правилам примешанного типа; в противном случае все члены вычисляются как [`True`](https://python-all.ru/3.11/library/constants.html#True). Чтобы логическое значение вашего перечисления зависело от значения члена, добавьте в свой класс следующее:932933```python934def __bool__(self):935    return bool(self.value)936```937938Простые классы [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) всегда вычисляются как [`True`](https://python-all.ru/3.11/library/constants.html#True).939940#### `Enum` классы с методами941942Если добавить в подкласс перечисления дополнительные методы, например, как в классе [Planet](https://python-all.ru/3.11/howto/enum.html#planet) ниже, эти методы появятся в [`dir()`](https://python-all.ru/3.11/library/functions.html#dir) элемента, но не класса:943944```python945>>> dir(Planet)                         946['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__members__', '__module__']947>>> dir(Planet.EARTH)                   948['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', 'surface_gravity', 'value']949```950951#### Объединение элементов `Flag`952953Итерация по комбинации элементов [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag) вернёт только те элементы, которые состоят из одного бита:954955```python956>>> class Color(Flag):957...     RED = auto()958...     GREEN = auto()959...     BLUE = auto()960...     MAGENTA = RED | BLUE961...     YELLOW = RED | GREEN962...     CYAN = GREEN | BLUE963...964>>> Color(3)  # именованная комбинация965<Color.YELLOW: 3>966>>> Color(7)      # не именованная комбинация967<Color.RED|GREEN|BLUE: 7>968```969970#### `Flag` и `IntFlag` мелочи971972Используя следующий фрагмент для примеров:973974```python975>>> class Color(IntFlag):976...     BLACK = 0977...     RED = 1978...     GREEN = 2979...     BLUE = 4980...     PURPLE = RED | BLUE981...     WHITE = RED | GREEN | BLUE982...983```984985верно следующее:986987- однобитовые флаги являются каноническими988- многобитовые и нулевые флаги являются псевдонимами989- при итерации возвращаются только канонические флаги:990991  ```python992  >>> list(Color.WHITE)993  [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]994  ```995- отрицание флага или набора флагов возвращает новый флаг/набор флагов с соответствующим положительным целым значением:996997  ```python998  >>> Color.BLUE999  <Color.BLUE: 4>10001001  >>> ~Color.BLUE1002  <Color.RED|GREEN: 3>1003  ```1004- имена псевдофлагов формируются из имён их элементов:10051006  ```python1007  >>> (Color.RED | Color.GREEN).name1008  'RED|GREEN'1009  ```1010- многобитовые флаги, также известные как псевдонимы, могут возвращаться в результате операций:10111012  ```python1013  >>> Color.RED | Color.BLUE1014  <Color.PURPLE: 5>10151016  >>> Color(7)  # или Color(-1)1017  <Color.WHITE: 7>10181019  >>> Color(0)1020  <Color.BLACK: 0>1021  ```1022- проверка членства/включения: нулевые флаги всегда считаются содержащимися:10231024  ```python1025  >>> Color.BLACK in Color.WHITE1026  True1027  ```10281029  в противном случае True возвращается, только если все биты одного флага содержатся в другом флаге:10301031  ```python1032  >>> Color.PURPLE in Color.WHITE1033  True10341035  >>> Color.GREEN in Color.PURPLE1036  False1037  ```10381039Появился новый механизм границ, который управляет обработкой выходящих за пределы / недопустимых битов: `STRICT`, `CONFORM`, `EJECT` и `KEEP`:10401041- STRICT –\> вызывает исключение при получении недопустимых значений1042- CONFORM –\> отбрасывает любые недопустимые биты1043- EJECT –\> теряет статус Flag и становится обычным int с заданным значением1044- KEEP –\> сохраняет дополнительные биты10451046  - сохраняет статус Flag и дополнительные биты1047  - дополнительные биты не отображаются при итерации1048  - дополнительные биты отображаются в repr() и str()10491050По умолчанию для Flag используется `STRICT`, по умолчанию для `IntFlag``EJECT`, а по умолчанию для `_convert_``KEEP` (см. `ssl.Options` для примера, когда требуется `KEEP`).10511052## Чем отличаются перечисления и флаги?10531054Перечисления имеют собственный метакласс, который влияет на многие аспекты как производных классов [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum), так и их экземпляров (элементов).10551056### Классы Enum10571058Метакласс [`EnumType`](https://python-all.ru/3.11/library/enum.html#enum.EnumType) отвечает за предоставление методов `__contains__()`, `__dir__()`, `__iter__()` и других, которые позволяют выполнять с классом [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) действия, невозможные для обычного класса, например, `list(Color)` или `some_enum_var in Color`. [`EnumType`](https://python-all.ru/3.11/library/enum.html#enum.EnumType) отвечает за обеспечение корректности различных других методов итогового класса [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) (таких как `__new__()`, `__getnewargs__()`, `__str__()` и `__repr__()`).10591060### Классы Flag10611062Флаги имеют расширенное представление о псевдонимах: чтобы быть каноническим, значение флага должно быть степенью двойки и не быть дублирующимся именем. Таким образом, в дополнение к определению псевдонима [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum), флаг без значения (также известный как `0`) или с более чем одним значением, являющимся степенью двойки (например, `3`), считается псевдонимом.10631064### Элементы Enum (также известные как экземпляры)10651066Самое интересное в членах перечисления – то, что они синглтоны. [`EnumType`](https://python-all.ru/3.11/library/enum.html#enum.EnumType) создаёт их все при создании самого класса перечисления, а затем подставляет собственный `__new__()`, чтобы гарантировать, что новые экземпляры никогда не будут созданы, возвращая только существующие.10671068### Члены флага10691070Члены флага можно перебирать так же, как и класс [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag), и будут возвращены только канонические члены. Например:10711072```python1073>>> list(Color)1074[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]1075```10761077(Обратите внимание, что `BLACK`, `PURPLE` и `WHITE` не отображаются.)10781079Инвертирование члена флага возвращает соответствующее положительное значение, а не отрицательное. Например:10801081```python1082>>> ~Color.RED1083<Color.GREEN|BLUE: 6>1084```10851086Члены флага имеют длину, соответствующую количеству содержащихся в них степеней двойки. Например:10871088```python1089>>> len(Color.PURPLE)109021091```10921093## Сборник рецептов Enum10941095Хотя [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum), [`IntEnum`](https://python-all.ru/3.11/library/enum.html#enum.IntEnum), [`StrEnum`](https://python-all.ru/3.11/library/enum.html#enum.StrEnum), [`Flag`](https://python-all.ru/3.11/library/enum.html#enum.Flag) и [`IntFlag`](https://python-all.ru/3.11/library/enum.html#enum.IntFlag) призваны покрывать большинство сценариев использования, они не могут охватить их все. Здесь приведены рецепты для некоторых различных типов перечислений, которые можно использовать напрямую или в качестве примеров для создания собственных.10961097### Пропуск значений10981099Во многих сценариях пользователю всё равно, каково фактическое значение перечисления. Существует несколько способов определить такой простой тип перечисления:11001101- использовать экземпляры [`auto`](https://python-all.ru/3.11/library/enum.html#enum.auto) в качестве значения1102- использовать экземпляры [`object`](https://python-all.ru/3.11/library/functions.html#object) в качестве значения1103- использовать описательную строку в качестве значения1104- использовать кортеж в качестве значения и собственный `__new__()` для замены кортежа на значение [`int`](https://python-all.ru/3.11/library/functions.html#int)11051106Использование любого из этих методов показывает пользователю, что эти значения не важны, а также позволяет добавлять, удалять или переупорядочивать члены без необходимости перенумерации остальных членов.11071108#### Использование [`auto`](https://python-all.ru/3.11/library/enum.html#enum.auto)11091110Использование [`auto`](https://python-all.ru/3.11/library/enum.html#enum.auto) будет выглядеть так:11111112```python1113>>> class Color(Enum):1114...     RED = auto()1115...     BLUE = auto()1116...     GREEN = auto()1117...1118>>> Color.GREEN1119<Color.GREEN: 3>1120```11211122#### Использование [`object`](https://python-all.ru/3.11/library/functions.html#object)11231124Использование [`object`](https://python-all.ru/3.11/library/functions.html#object) будет выглядеть так:11251126```python1127>>> class Color(Enum):1128...     RED = object()1129...     GREEN = object()1130...     BLUE = object()1131...1132>>> Color.GREEN                         1133<Color.GREEN: <object object at 0x...>>1134```11351136Это также хороший пример того, зачем может понадобиться написать собственный `__repr__()`:11371138```python1139>>> class Color(Enum):1140...     RED = object()1141...     GREEN = object()1142...     BLUE = object()1143...     def __repr__(self):1144...         return "<%s.%s>" % (self.__class__.__name__, self._name_)1145...1146>>> Color.GREEN1147<Color.GREEN>1148```11491150#### Использование описательной строки11511152Использование строки в качестве значения будет выглядеть так:11531154```python1155>>> class Color(Enum):1156...     RED = 'stop'1157...     GREEN = 'go'1158...     BLUE = 'too fast!'1159...1160>>> Color.GREEN1161<Color.GREEN: 'go'>1162```11631164#### Использование собственного `__new__()`11651166Использование автонумерующего `__new__()` будет выглядеть так:11671168```python1169>>> class AutoNumber(Enum):1170...     def __new__(cls):1171...         value = len(cls.__members__) + 11172...         obj = object.__new__(cls)1173...         obj._value_ = value1174...         return obj1175...1176>>> class Color(AutoNumber):1177...     RED = ()1178...     GREEN = ()1179...     BLUE = ()1180...1181>>> Color.GREEN1182<Color.GREEN: 2>1183```11841185Чтобы сделать более универсальный `AutoNumber`, добавьте `*args` в сигнатуру:11861187```python1188>>> class AutoNumber(Enum):1189...     def __new__(cls, *args):      # это единственное изменение по сравнению с предыдущим1190...         value = len(cls.__members__) + 11191...         obj = object.__new__(cls)1192...         obj._value_ = value1193...         return obj1194...1195```11961197Затем при наследовании от `AutoNumber` можно написать собственный `__init__` для обработки любых дополнительных аргументов:11981199```python1200>>> class Swatch(AutoNumber):1201...     def __init__(self, pantone='unknown'):1202...         self.pantone = pantone1203...     AUBURN = '3497'1204...     SEA_GREEN = '1246'1205...     BLEACHED_CORAL = () # Новый цвет, кода Pantone пока нет!1206...1207>>> Swatch.SEA_GREEN1208<Swatch.SEA_GREEN: 2>1209>>> Swatch.SEA_GREEN.pantone1210'1246'1211>>> Swatch.BLEACHED_CORAL.pantone1212'unknown'1213```12141215> **Примечание**1216>1217> Метод `__new__()`, если он определён, используется во время создания членов Enum; затем он заменяется методом `__new__()` класса Enum, который используется после создания класса для поиска существующих членов.12181219> **Предупреждение**1220>1221> *Не вызывайте* `super().__new__()`, так как будет найден `__new__` только для поиска; вместо этого используйте непосредственно тип данных – например:1222>1223> ```python1224> obj = int.__new__(cls, value)1225> ```12261227### OrderedEnum12281229Упорядоченное перечисление, которое не основано на [`IntEnum`](https://python-all.ru/3.11/library/enum.html#enum.IntEnum) и поэтому сохраняет обычные инварианты [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) (например, несравнимость с другими перечислениями):12301231```python1232>>> class OrderedEnum(Enum):1233...     def __ge__(self, other):1234...         if self.__class__ is other.__class__:1235...             return self.value >= other.value1236...         return NotImplemented1237...     def __gt__(self, other):1238...         if self.__class__ is other.__class__:1239...             return self.value > other.value1240...         return NotImplemented1241...     def __le__(self, other):1242...         if self.__class__ is other.__class__:1243...             return self.value <= other.value1244...         return NotImplemented1245...     def __lt__(self, other):1246...         if self.__class__ is other.__class__:1247...             return self.value < other.value1248...         return NotImplemented1249...1250>>> class Grade(OrderedEnum):1251...     A = 51252...     B = 41253...     C = 31254...     D = 21255...     F = 11256...1257>>> Grade.C < Grade.A1258True1259```12601261### DuplicateFreeEnum12621263Вызывает ошибку, если обнаружено повторяющееся значение члена, вместо создания псевдонима:12641265```python1266>>> class DuplicateFreeEnum(Enum):1267...     def __init__(self, *args):1268...         cls = self.__class__1269...         if any(self.value == e.value for e in cls):1270...             a = self.name1271...             e = cls(self.value).name1272...             raise ValueError(1273...                 "aliases not allowed in DuplicateFreeEnum:  %r --> %r"1274...                 % (a, e))1275...1276>>> class Color(DuplicateFreeEnum):1277...     RED = 11278...     GREEN = 21279...     BLUE = 31280...     GRENE = 21281...1282Traceback (most recent call last):1283  ...1284ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'1285```12861287> **Примечание**1288>1289> Это полезный пример подкласса Enum для добавления или изменения другого поведения, а также запрета псевдонимов. Если требуется только запрет псевдонимов, вместо этого можно использовать декоратор [`unique()`](https://python-all.ru/3.11/library/enum.html#enum.unique).12901291### Planet12921293Если определены `__new__()` или `__init__()`, значение элемента перечисления будет передаваться этим методам:12941295```python1296>>> class Planet(Enum):1297...     MERCURY = (3.303e+23, 2.4397e6)1298...     VENUS   = (4.869e+24, 6.0518e6)1299...     EARTH   = (5.976e+24, 6.37814e6)1300...     MARS    = (6.421e+23, 3.3972e6)1301...     JUPITER = (1.9e+27,   7.1492e7)1302...     SATURN  = (5.688e+26, 6.0268e7)1303...     URANUS  = (8.686e+25, 2.5559e7)1304...     NEPTUNE = (1.024e+26, 2.4746e7)1305...     def __init__(self, mass, radius):1306...         self.mass = mass       # в килограммах1307...         self.radius = radius   # в метрах1308...     @property1309...     def surface_gravity(self):1310...         # гравитационная постоянная (м3 кг-1 с-2)1311...         G = 6.67300E-111312...         return G * self.mass / (self.radius * self.radius)1313...1314>>> Planet.EARTH.value1315(5.976e+24, 6378140.0)1316>>> Planet.EARTH.surface_gravity13179.8026527433371291318```13191320### TimePeriod13211322Пример использования атрибута `_ignore_`:13231324```python1325>>> from datetime import timedelta1326>>> class Period(timedelta, Enum):1327...     "different lengths of time"1328...     _ignore_ = 'Period i'1329...     Period = vars()1330...     for i in range(367):1331...         Period['day_%d' % i] = i1332...1333>>> list(Period)[:2]1334[<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]1335>>> list(Period)[-2:]1336[<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]1337```13381339## Создание подкласса EnumType13401341Хотя большинство потребностей в перечислениях можно удовлетворить, настраивая подклассы [`Enum`](https://python-all.ru/3.11/library/enum.html#enum.Enum) с помощью декораторов классов или пользовательских функций, [`EnumType`](https://python-all.ru/3.11/library/enum.html#enum.EnumType) можно субклассировать для получения другого опыта работы с Enum.1342