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

enum.md

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

1> **Источник:** https://python-all.ru/3.8/library/enum.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# [`enum`](https://python-all.ru/3.8/library/enum.html#module-enum) – Поддержка перечислений89Новое в версии 3.4.1011**Исходный код:** [Lib/enum.py](https://python-all.ru/src/3.8/Lib/enum.py)1213---1415Перечисление – это набор символических имён (членов), привязанных к уникальным постоянным значениям. Внутри перечисления члены можно сравнивать по идентичности, а само перечисление можно перебирать.1617> **Примечание**18>19> Регистр имён членов перечисления20>21> Поскольку перечисления используются для представления констант, рекомендуется использовать имена в ВЕРХНЕМ\_РЕГИСТРЕ для членов перечисления, и мы будем использовать этот стиль в наших примерах.2223## Содержимое модуля2425Этот модуль определяет четыре класса перечислений, которые можно использовать для определения уникальных наборов имён и значений: [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum), [`IntEnum`](https://python-all.ru/3.8/library/enum.html#enum.IntEnum), [`Flag`](https://python-all.ru/3.8/library/enum.html#enum.Flag) и [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag). Также он определяет один декоратор [`unique()`](https://python-all.ru/3.8/library/enum.html#enum.unique) и один вспомогательный класс [`auto`](https://python-all.ru/3.8/library/enum.html#enum.auto).2627#### `class enum.Enum`2829Базовый класс для создания перечислимых констант. См. раздел [Функциональный API](https://python-all.ru/3.8/library/enum.html#functional-api) для альтернативного синтаксиса создания.3031#### `class enum.IntEnum`3233Базовый класс для создания перечислимых констант, которые также являются подклассами [`int`](https://python-all.ru/3.8/library/functions.html#int).3435#### `class enum.IntFlag`3637Базовый класс для создания перечислимых констант, которые можно комбинировать с помощью побитовых операторов, не теряя принадлежности к [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag). Члены [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag) также являются подклассами [`int`](https://python-all.ru/3.8/library/functions.html#int).3839#### `class enum.Flag`4041Базовый класс для создания перечисляемых констант, которые можно комбинировать с помощью побитовых операций без потери их принадлежности к [`Flag`](https://python-all.ru/3.8/library/enum.html#enum.Flag).4243#### `enum.unique()`4445Декоратор класса перечисления, который гарантирует, что каждому значению соответствует только одно имя.4647#### `class enum.auto`4849Экземпляры заменяются подходящим значением для элементов Enum. Начальное значение – 1.5051Новое в версии 3.6: `Flag`, `IntFlag`, `auto`5253## Создание перечисления5455Перечисления создаются с использованием синтаксиса [`class`](https://python-all.ru/3.8/reference/compound_stmts.html#class), что делает их легко читаемыми и удобными для записи. Альтернативный метод создания описан в [Функциональный API](https://python-all.ru/3.8/library/enum.html#functional-api). Чтобы определить перечисление, создайте подкласс [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) следующим образом:5657```python58>>> from enum import Enum59>>> class Color(Enum):60...     RED = 161...     GREEN = 262...     BLUE = 363...64```6566> **Примечание**67>68> Значения членов Enum69>70> Значения членов могут быть любыми: [`int`](https://python-all.ru/3.8/library/functions.html#int), [`str`](https://python-all.ru/3.8/library/stdtypes.html#str) и т.д. Если точное значение неважно, можно использовать экземпляры [`auto`](https://python-all.ru/3.8/library/enum.html#enum.auto), и подходящее значение будет выбрано автоматически. Следует соблюдать осторожность при смешивании [`auto`](https://python-all.ru/3.8/library/enum.html#enum.auto) с другими значениями.7172> **Примечание**73>74> Терминология75>76> - Класс `Color` является *перечислением* (или *enum*)77> - Атрибуты `Color.RED`, `Color.GREEN` и т.д. являются *членами перечисления* (или *членами перечисления*) и по сути являются константами.78> - Члены перечисления имеют *имена* и *значения* (имя `Color.RED` – `RED`, значение `Color.BLUE` – `3` и т.д.)7980> **Примечание**81>82> Хотя для создания перечислений мы используем синтаксис [`class`](https://python-all.ru/3.8/reference/compound_stmts.html#class), перечисления не являются обычными классами Python. Подробнее см. [Чем отличаются перечисления?](https://python-all.ru/3.8/library/enum.html#how-are-enums-different).8384Члены перечисления имеют удобочитаемые строковые представления:8586```python87>>> print(Color.RED)88Color.RED89```9091…в то время как их `repr` содержит больше информации:9293```python94>>> print(repr(Color.RED))95<Color.RED: 1>96```9798*Тип* члена перечисления – это перечисление, к которому он принадлежит:99100```python101>>> type(Color.RED)102<enum 'Color'>103>>> isinstance(Color.GREEN, Color)104True105>>>106```107108Члены перечисления также имеют свойство, содержащее только их имя:109110```python111>>> print(Color.RED.name)112RED113```114115Перечисления поддерживают итерацию в порядке определения:116117```python118>>> class Shake(Enum):119...     VANILLA = 7120...     CHOCOLATE = 4121...     COOKIES = 9122...     MINT = 3123...124>>> for shake in Shake:125...     print(shake)126...127Shake.VANILLA128Shake.CHOCOLATE129Shake.COOKIES130Shake.MINT131```132133Члены перечисления хешируемы, поэтому их можно использовать в словарях и множествах:134135```python136>>> apples = {}137>>> apples[Color.RED] = 'red delicious'138>>> apples[Color.GREEN] = 'granny smith'139>>> apples == {Color.RED: 'red delicious', Color.GREEN: 'granny smith'}140True141```142143## Программный доступ к членам перечисления и их атрибутам144145Иногда бывает полезно обращаться к членам перечисления программно (например, в ситуациях, когда `Color.RED` не подходит, поскольку точный цвет неизвестен на момент написания программы). `Enum` предоставляет такой доступ:146147```python148>>> Color(1)149<Color.RED: 1>150>>> Color(3)151<Color.BLUE: 3>152```153154Если требуется обратиться к членам перечисления по *имени*, используйте доступ по ключу:155156```python157>>> Color['RED']158<Color.RED: 1>159>>> Color['GREEN']160<Color.GREEN: 2>161```162163Если есть член перечисления и требуется его `name` или `value`:164165```python166>>> member = Color.RED167>>> member.name168'RED'169>>> member.value1701171```172173## Дублирование членов и значений перечисления174175Наличие двух членов перечисления с одинаковым именем недопустимо:176177```python178>>> class Shape(Enum):179...     SQUARE = 2180...     SQUARE = 3181...182Traceback (most recent call last):183...184TypeError: Attempted to reuse key: 'SQUARE'185```186187Однако двум членам перечисления разрешено иметь одинаковое значение. Если два члена A и B имеют одинаковое значение (и A определён первым), то B является псевдонимом A. Поиск по значению A и B вернёт A. Поиск по имени B также вернёт A:188189```python190>>> class Shape(Enum):191...     SQUARE = 2192...     DIAMOND = 1193...     CIRCLE = 3194...     ALIAS_FOR_SQUARE = 2195...196>>> Shape.SQUARE197<Shape.SQUARE: 2>198>>> Shape.ALIAS_FOR_SQUARE199<Shape.SQUARE: 2>200>>> Shape(2)201<Shape.SQUARE: 2>202```203204> **Примечание**205>206> Попытка создать член с тем же именем, что и уже определённый атрибут (другой член, метод и т.д.), или попытка создать атрибут с тем же именем, что и член, не допускается.207208## Обеспечение уникальности значений перечисления209210По умолчанию перечисления допускают несколько имён в качестве псевдонимов для одного и того же значения. Если такое поведение нежелательно, можно использовать следующий декоратор, чтобы гарантировать, что каждое значение используется в перечислении только один раз:211212#### `@enum.unique`213214Декоратор [`class`](https://python-all.ru/3.8/reference/compound_stmts.html#class), предназначенный специально для перечислений. Он просматривает `__members__` перечисления, собирая все найденные псевдонимы; если таковые обнаружены, возбуждается [`ValueError`](https://python-all.ru/3.8/library/exceptions.html#ValueError) с подробностями.215216```python217>>> from enum import Enum, unique218>>> @unique219... class Mistake(Enum):220...     ONE = 1221...     TWO = 2222...     THREE = 3223...     FOUR = 3224...225Traceback (most recent call last):226...227ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE228```229230## Использование автоматических значений231232Если точное значение неважно, можно использовать [`auto`](https://python-all.ru/3.8/library/enum.html#enum.auto):233234```python235>>> from enum import Enum, auto236>>> class Color(Enum):237...     RED = auto()238...     BLUE = auto()239...     GREEN = auto()240...241>>> list(Color)242[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]243```244245Значения выбираются с помощью `_generate_next_value_()`, который можно переопределить:246247```python248>>> class AutoName(Enum):249...     def _generate_next_value_(name, start, count, last_values):250...         return name251...252>>> class Ordinal(AutoName):253...     NORTH = auto()254...     SOUTH = auto()255...     EAST = auto()256...     WEST = auto()257...258>>> list(Ordinal)259[<Ordinal.NORTH: 'NORTH'>, <Ordinal.SOUTH: 'SOUTH'>, <Ordinal.EAST: 'EAST'>, <Ordinal.WEST: 'WEST'>]260```261262> **Примечание**263>264> Цель метода по умолчанию `_generate_next_value_()` – предоставить следующий [`int`](https://python-all.ru/3.8/library/functions.html#int) в последовательности с последним предоставленным [`int`](https://python-all.ru/3.8/library/functions.html#int), но способ, которым это делается, является деталью реализации и может измениться.265266> **Примечание**267>268> Метод `_generate_next_value_()` должен быть определён до любых членов.269270## Перебор271272Перебор членов перечисления не включает псевдонимы:273274```python275>>> list(Shape)276[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]277```278279Специальный атрибут `__members__` – это упорядоченное отображение имён на члены, доступное только для чтения. Он включает все имена, определённые в перечислении, включая псевдонимы:280281```python282>>> for name, member in Shape.__members__.items():283...     name, member284...285('SQUARE', <Shape.SQUARE: 2>)286('DIAMOND', <Shape.DIAMOND: 1>)287('CIRCLE', <Shape.CIRCLE: 3>)288('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)289```290291Атрибут `__members__` можно использовать для детального программного доступа к членам перечисления. Например, для поиска всех псевдонимов:292293```python294>>> [name for name, member in Shape.__members__.items() if member.name != name]295['ALIAS_FOR_SQUARE']296```297298## Сравнения299300Члены перечисления сравниваются по идентичности:301302```python303>>> Color.RED is Color.RED304True305>>> Color.RED is Color.BLUE306False307>>> Color.RED is not Color.BLUE308True309```310311Упорядоченные сравнения между значениями перечисления *не* поддерживаются. Члены перечисления – не целые числа (но см. [IntEnum](https://python-all.ru/3.8/library/enum.html#intenum) ниже):312313```python314>>> Color.RED < Color.BLUE315Traceback (most recent call last):316  File "<stdin>", line 1, in <module>317TypeError: '<' not supported between instances of 'Color' and 'Color'318```319320Однако сравнения на равенство определены:321322```python323>>> Color.BLUE == Color.RED324False325>>> Color.BLUE != Color.RED326True327>>> Color.BLUE == Color.BLUE328True329```330331Сравнения со значениями, не являющимися перечислениями, всегда дают результат «не равно» (опять же, [`IntEnum`](https://python-all.ru/3.8/library/enum.html#enum.IntEnum) был явно спроектирован для другого поведения, см. ниже):332333```python334>>> Color.BLUE == 2335False336```337338## Допустимые члены и атрибуты перечислений339340В примерах выше для значений перечислений используются целые числа. Использование целых чисел – это кратко и удобно (и предусмотрено по умолчанию [функциональным API](https://python-all.ru/3.8/library/enum.html#functional-api)), но не является строгим требованием. В подавляющем большинстве случаев не важно, каково фактическое значение элемента перечисления. Но если значение *является* важным, перечисления могут иметь произвольные значения.341342Перечисления – это классы Python и могут иметь обычные методы и специальные методы. Если есть такое перечисление:343344```python345>>> class Mood(Enum):346...     FUNKY = 1347...     HAPPY = 3348...349...     def describe(self):350...         # self – это член перечисления351...         return self.name, self.value352...353...     def __str__(self):354...         return 'my custom str! {0}'.format(self.value)355...356...     @classmethod357...     def favorite_mood(cls):358...         # cls здесь – это перечисление359...         return cls.HAPPY360...361```362363Тогда:364365```python366>>> Mood.favorite_mood()367<Mood.HAPPY: 3>368>>> Mood.HAPPY.describe()369('HAPPY', 3)370>>> str(Mood.FUNKY)371'my custom str! 1'372```373374Правила допустимого таковы: имена, которые начинаются и заканчиваются одним подчёркиванием, зарезервированы для enum и не могут использоваться; все остальные атрибуты, определённые внутри перечисления, становятся его членами, за исключением специальных методов ([`__str__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__str__), [`__add__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__add__) и т.д.), дескрипторов (методы тоже являются дескрипторами) и имён переменных, перечисленных в `_ignore_`.375376Примечание: если в перечислении определены [`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__) и/или [`__init__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__init__), то все значения, переданные элементу перечисления, будут переданы в эти методы. В качестве примера см. [Planet](https://python-all.ru/3.8/library/enum.html#planet).377378## Ограниченное создание подклассов Enum379380Новый класс [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) должен иметь один базовый класс Enum, не более одного конкретного типа данных и столько [`object`](https://python-all.ru/3.8/library/functions.html#object)-основанных классов-примесей, сколько необходимо. Порядок этих базовых классов:381382```python383class EnumName([mix-in, ...,] [data-type,] base-enum):384    pass385```386387Также создание подкласса перечисления разрешено только в том случае, если перечисление не определяет никаких членов. Поэтому это запрещено:388389```python390>>> class MoreColor(Color):391...     PINK = 17392...393Traceback (most recent call last):394...395TypeError: Cannot extend enumerations396```397398Но это разрешено:399400```python401>>> class Foo(Enum):402...     def some_behavior(self):403...         pass404...405>>> class Bar(Foo):406...     HAPPY = 1407...     SAD = 2408...409```410411Разрешение создания подклассов перечислений, определяющих члены, привело бы к нарушению некоторых важных инвариантов типов и экземпляров. С другой стороны, имеет смысл разрешить общее поведение для группы перечислений. (Пример см. в [OrderedEnum](https://python-all.ru/3.8/library/enum.html#orderedenum).)412413## Пиклинг414415Перечисления могут быть упакованы и распакованы с помощью модуля pickle.416417```python418>>> from test.test_enum import Fruit419>>> from pickle import dumps, loads420>>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))421True422```423424Обычные ограничения для упаковки с помощью модуля pickle применяются: перечисления, которые можно упаковать, должны быть определены на верхнем уровне модуля, так как для распаковки их нужно импортировать из этого модуля.425426> **Примечание**427>428> С протоколом pickle версии 4 можно легко упаковывать перечисления, вложенные в другие классы.429430Можно изменить способ сериализации/десериализации членов Enum, определив [`__reduce_ex__()`](https://python-all.ru/3.8/library/pickle.html#object.__reduce_ex__) в классе перечисления.431432## Функциональное API433434Класс [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) является вызываемым и предоставляет следующее функциональное API:435436```python437>>> Animal = Enum('Animal', 'ANT BEE CAT DOG')438>>> Animal439<enum 'Animal'>440>>> Animal.ANT441<Animal.ANT: 1>442>>> Animal.ANT.value4431444>>> list(Animal)445[<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]446```447448Семантика этого API напоминает [`namedtuple`](https://python-all.ru/3.8/library/collections.html#collections.namedtuple). Первый аргумент вызова [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) – это имя перечисления.449450Второй аргумент – это *источник* имён членов перечисления. Это может быть строка имён, разделённых пробелами, последовательность имён, последовательность двухэлементных кортежей с парами ключ/значение или отображение (например, словарь) имён на значения. Последние два варианта позволяют присваивать произвольные значения перечислениям; остальные автоматически присваивают увеличивающиеся целые числа, начиная с 1 (используйте параметр `start` для указания другого начального значения). Возвращается новый класс, производный от [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum). Другими словами, приведённое выше присваивание `Animal` эквивалентно:451452```python453>>> class Animal(Enum):454...     ANT = 1455...     BEE = 2456...     CAT = 3457...     DOG = 4458...459```460461Причина, по которой по умолчанию используется `1`, а не `0`, заключается в том, что `0` равно `False` с точки зрения булевой логики, но все члены перечисления вычисляются в `True`.462463Сериализация перечислений, созданных с помощью функционального API, может быть сложной, поскольку для определения модуля, в котором создаётся перечисление, используются детали реализации стека вызовов (например, это не сработает, если использовать вспомогательную функцию в отдельном модуле, а также может не работать в IronPython или Jython). Решение – явно указать имя модуля следующим образом:464465```python466>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)467```468469> **Предупреждение**470>471> Если `module` не указан, и Enum не может его определить, новые члены Enum не будут поддерживать распаковку; чтобы ошибки были ближе к источнику, pickling будет отключён.472473Новый протокол pickle 4 также в некоторых обстоятельствах полагается на то, что [`__qualname__`](https://python-all.ru/3.8/library/stdtypes.html#definition.__qualname__) установлен в расположение, где pickle сможет найти класс. Например, если класс стал доступен в классе SomeData в глобальной области видимости:474475```python476>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')477```478479Полная сигнатура:480481```python482Enum(value='NewEnumName', names=<...>, *, module='...', qualname='...', type=<mixed-in class>, start=1)483```484485**значение**486487Что новый класс Enum запишет в качестве своего имени.488489**имена**490491Члены перечисления. Это может быть строка, разделённая пробелами или запятыми (значения будут начинаться с 1, если не указано иное):492493```python494'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'495```496497или итератор имён:498499```python500['RED', 'GREEN', 'BLUE']501```502503или итератор пар (имя, значение):504505```python506[('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]507```508509или отображение:510511```python512{'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}513```514515**модуль**516517имя модуля, в котором находится новый класс Enum.518519**qualname**520521где в модуле находится новый класс Enum.522523**тип**524525тип, который следует примешать к новому классу Enum.526527**start**528529число, с которого начинать отсчёт, если переданы только имена.530531Изменено в версии 3.5: Добавлен параметр *start*.532533## Производные перечисления534535### IntEnum536537Первая разновидность [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) также является подклассом [`int`](https://python-all.ru/3.8/library/functions.html#int). Элементы [`IntEnum`](https://python-all.ru/3.8/library/enum.html#enum.IntEnum) можно сравнивать с целыми числами; соответственно, целочисленные перечисления разных типов также можно сравнивать друг с другом:538539```python540>>> from enum import IntEnum541>>> class Shape(IntEnum):542...     CIRCLE = 1543...     SQUARE = 2544...545>>> class Request(IntEnum):546...     POST = 1547...     GET = 2548...549>>> Shape == 1550False551>>> Shape.CIRCLE == 1552True553>>> Shape.CIRCLE == Request.POST554True555```556557Однако их по-прежнему нельзя сравнивать со стандартными перечислениями [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum):558559```python560>>> class Shape(IntEnum):561...     CIRCLE = 1562...     SQUARE = 2563...564>>> class Color(Enum):565...     RED = 1566...     GREEN = 2567...568>>> Shape.CIRCLE == Color.RED569False570```571572Значения [`IntEnum`](https://python-all.ru/3.8/library/enum.html#enum.IntEnum) ведут себя как целые числа и в других ожидаемых аспектах:573574```python575>>> int(Shape.CIRCLE)5761577>>> ['a', 'b', 'c'][Shape.CIRCLE]578'b'579>>> [i for i in range(Shape.SQUARE)]580[0, 1]581```582583### IntFlag584585Следующая вариация [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum), а именно [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag), также основана на [`int`](https://python-all.ru/3.8/library/functions.html#int). Разница в том, что члены [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag) можно объединять с помощью побитовых операторов (&, |, ^, ~), и результат всё ещё остаётся членом [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag). Однако, как следует из названия, члены [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag) также являются подклассами [`int`](https://python-all.ru/3.8/library/functions.html#int) и могут использоваться везде, где используется [`int`](https://python-all.ru/3.8/library/functions.html#int). Любая операция над членом [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag), кроме побитовых операций, приведёт к потере его принадлежности к [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag).586587Новое в версии 3.6.588589Пример класса [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag):590591```python592>>> from enum import IntFlag593>>> class Perm(IntFlag):594...     R = 4595...     W = 2596...     X = 1597...598>>> Perm.R | Perm.W599<Perm.R|W: 6>600>>> Perm.R + Perm.W6016602>>> RW = Perm.R | Perm.W603>>> Perm.R in RW604True605```606607Также можно давать имена комбинациям:608609```python610>>> class Perm(IntFlag):611...     R = 4612...     W = 2613...     X = 1614...     RWX = 7615>>> Perm.RWX616<Perm.RWX: 7>617>>> ~Perm.RWX618<Perm.-8: -8>619```620621Ещё одно важное отличие между [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag) и [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) в том, что если ни один флаг не установлен (значение равно 0), то его логическое значение – [`False`](https://python-all.ru/3.8/library/constants.html#False):622623```python624>>> Perm.R & Perm.X625<Perm.0: 0>626>>> bool(Perm.R & Perm.X)627False628```629630Поскольку члены [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag) также являются подклассами [`int`](https://python-all.ru/3.8/library/functions.html#int), их можно объединять с ними:631632```python633>>> Perm.X | 8634<Perm.8|X: 9>635```636637### Flag638639Последняя разновидность – [`Flag`](https://python-all.ru/3.8/library/enum.html#enum.Flag). Как и [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag), элементы [`Flag`](https://python-all.ru/3.8/library/enum.html#enum.Flag) можно комбинировать с помощью побитовых операторов (&, |, ^, ~). В отличие от [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag), их нельзя комбинировать или сравнивать ни с каким другим перечислением [`Flag`](https://python-all.ru/3.8/library/enum.html#enum.Flag), а также с [`int`](https://python-all.ru/3.8/library/functions.html#int). Хотя можно задавать значения напрямую, рекомендуется использовать [`auto`](https://python-all.ru/3.8/library/enum.html#enum.auto) в качестве значения и позволить [`Flag`](https://python-all.ru/3.8/library/enum.html#enum.Flag) выбрать подходящее значение.640641Новое в версии 3.6.642643Как и в случае с [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag), если комбинация элементов [`Flag`](https://python-all.ru/3.8/library/enum.html#enum.Flag) не содержит установленных флагов, логическое значение равно [`False`](https://python-all.ru/3.8/library/constants.html#False):644645```python646>>> from enum import Flag, auto647>>> class Color(Flag):648...     RED = auto()649...     BLUE = auto()650...     GREEN = auto()651...652>>> Color.RED & Color.GREEN653<Color.0: 0>654>>> bool(Color.RED & Color.GREEN)655False656```657658Отдельные флаги должны иметь значения, являющиеся степенями двойки (1, 2, 4, 8, …), в то время как комбинации флагов – нет:659660```python661>>> class Color(Flag):662...     RED = auto()663...     BLUE = auto()664...     GREEN = auto()665...     WHITE = RED | BLUE | GREEN666...667>>> Color.WHITE668<Color.WHITE: 7>669```670671Присвоение имени условию «флаги не установлены» не меняет его логическое значение:672673```python674>>> class Color(Flag):675...     BLACK = 0676...     RED = auto()677...     BLUE = auto()678...     GREEN = auto()679...680>>> Color.BLACK681<Color.BLACK: 0>682>>> bool(Color.BLACK)683False684```685686> **Примечание**687>688> Для большинства нового кода настоятельно рекомендуются [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) и [`Flag`](https://python-all.ru/3.8/library/enum.html#enum.Flag), поскольку [`IntEnum`](https://python-all.ru/3.8/library/enum.html#enum.IntEnum) и [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag) нарушают некоторые семантические обещания перечисления (будучи сравнимыми с целыми числами, а значит, по транзитивности, и с другими не связанными перечислениями). [`IntEnum`](https://python-all.ru/3.8/library/enum.html#enum.IntEnum) и [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag) следует использовать только в тех случаях, когда [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) и [`Flag`](https://python-all.ru/3.8/library/enum.html#enum.Flag) не подходят; например, при замене целочисленных констант на перечисления или для взаимодействия с другими системами.689690### Другие691692Хотя [`IntEnum`](https://python-all.ru/3.8/library/enum.html#enum.IntEnum) является частью модуля [`enum`](https://python-all.ru/3.8/library/enum.html#module-enum), его очень просто реализовать самостоятельно:693694```python695class IntEnum(int, Enum):696    pass697```698699Это показывает, как можно определить подобные производные перечисления; например, `StrEnum`, в который примешивается [`str`](https://python-all.ru/3.8/library/stdtypes.html#str) вместо [`int`](https://python-all.ru/3.8/library/functions.html#int).700701Некоторые правила:7027031. При создании подкласса [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) типы-примеси должны располагаться перед самим [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) в последовательности базовых классов, как в [`IntEnum`](https://python-all.ru/3.8/library/enum.html#enum.IntEnum) примере выше.7042. Хотя [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) может содержать элементы любого типа, как только к нему примешивается дополнительный тип, все элементы должны иметь значения этого типа, например [`int`](https://python-all.ru/3.8/library/functions.html#int) выше. Это ограничение не распространяется на примеси, которые только добавляют методы и не указывают другой тип данных, такие как [`int`](https://python-all.ru/3.8/library/functions.html#int) или [`str`](https://python-all.ru/3.8/library/stdtypes.html#str).7053. При примешивании другого типа данных атрибут `value` *отличается* от самого члена перечисления, хотя он эквивалентен и будет равным при сравнении.7064. Форматирование в стиле %: *%s* и *%r* вызывают методы [`__str__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__str__) и [`__repr__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__repr__) класса [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) соответственно; другие коды (например, *%i* или *%h* для IntEnum) обрабатывают член перечисления как его примешанный тип.7075. [Форматированные строковые литералы](https://python-all.ru/3.8/reference/lexical_analysis.html#f-strings), [`str.format()`](https://python-all.ru/3.8/library/stdtypes.html#str.format) и [`format()`](https://python-all.ru/3.8/library/functions.html#format) будут использовать [`__format__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__format__) примешанного типа, если только [`__str__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__str__) или [`__format__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__format__) не переопределены в подклассе; в этом случае будут использоваться переопределённые методы или методы [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum). Используйте коды формата !s и !r, чтобы принудительно использовать методы [`__str__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__str__) и [`__repr__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__repr__) класса [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum).708709## Когда использовать [`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__) или [`__init__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__init__)710711[`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__) следует использовать всякий раз, когда требуется настроить фактическое значение члена [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum). Любые другие изменения можно вносить как в [`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__), так и в [`__init__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__init__), при этом предпочтение отдаётся [`__init__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__init__).712713Например, если требуется передать конструктору несколько элементов, но только один из них должен быть значением:714715```python716>>> class Coordinate(bytes, Enum):717...     """718...     Согласование с двоичными кодами, которые можно индексировать по целочисленному коду.719...     """720...     def __new__(cls, value, label, unit):721...         obj = bytes.__new__(cls, [value])722...         obj._value_ = value723...         obj.label = label724...         obj.unit = unit725...         return obj726...     PX = (0, 'P.X', 'km')727...     PY = (1, 'P.Y', 'km')728...     VX = (2, 'V.X', 'km/s')729...     VY = (3, 'V.Y', 'km/s')730...731732>>> print(Coordinate['PY'])733Coordinate.PY734735>>> print(Coordinate(3))736Coordinate.VY737```738739## Интересные примеры740741Хотя ожидается, что [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum), [`IntEnum`](https://python-all.ru/3.8/library/enum.html#enum.IntEnum), [`IntFlag`](https://python-all.ru/3.8/library/enum.html#enum.IntFlag) и [`Flag`](https://python-all.ru/3.8/library/enum.html#enum.Flag) покрывают большинство случаев использования, они не могут охватить их все. Ниже приведены рецепты для некоторых других типов перечислений, которые можно использовать напрямую или как примеры для создания собственных.742743### Пропуск значений744745Во многих случаях использования неважно, каково фактическое значение элемента перечисления. Есть несколько способов определить такой простой тип перечисления:746747- использовать экземпляры [`auto`](https://python-all.ru/3.8/library/enum.html#enum.auto) в качестве значения748- использовать экземпляры [`object`](https://python-all.ru/3.8/library/functions.html#object) в качестве значения749- использовать описательную строку в качестве значения750- использовать кортеж в качестве значения и собственный [`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__) для замены кортежа на значение [`int`](https://python-all.ru/3.8/library/functions.html#int)751752Использование любого из этих методов показывает пользователю, что эти значения не важны, а также позволяет добавлять, удалять или переупорядочивать члены без необходимости перенумерации остальных членов.753754Какой бы метод ни был выбран, следует предоставить [`repr()`](https://python-all.ru/3.8/library/functions.html#repr), который также скрывает (неважное) значение:755756```python757>>> class NoValue(Enum):758...     def __repr__(self):759...         return '<%s.%s>' % (self.__class__.__name__, self.name)760...761```762763#### Использование [`auto`](https://python-all.ru/3.8/library/enum.html#enum.auto)764765Использование [`auto`](https://python-all.ru/3.8/library/enum.html#enum.auto) будет выглядеть так:766767```python768>>> class Color(NoValue):769...     RED = auto()770...     BLUE = auto()771...     GREEN = auto()772...773>>> Color.GREEN774<Color.GREEN>775```776777#### Использование [`object`](https://python-all.ru/3.8/library/functions.html#object)778779Использование [`object`](https://python-all.ru/3.8/library/functions.html#object) будет выглядеть так:780781```python782>>> class Color(NoValue):783...     RED = object()784...     GREEN = object()785...     BLUE = object()786...787>>> Color.GREEN788<Color.GREEN>789```790791#### Использование описательной строки792793Использование строки в качестве значения будет выглядеть так:794795```python796>>> class Color(NoValue):797...     RED = 'stop'798...     GREEN = 'go'799...     BLUE = 'too fast!'800...801>>> Color.GREEN802<Color.GREEN>803>>> Color.GREEN.value804'go'805```806807#### Использование собственного [`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__)808809Использование автонумерующего [`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__) будет выглядеть так:810811```python812>>> class AutoNumber(NoValue):813...     def __new__(cls):814...         value = len(cls.__members__) + 1815...         obj = object.__new__(cls)816...         obj._value_ = value817...         return obj818...819>>> class Color(AutoNumber):820...     RED = ()821...     GREEN = ()822...     BLUE = ()823...824>>> Color.GREEN825<Color.GREEN>826>>> Color.GREEN.value8272828```829830Чтобы сделать более универсальный `AutoNumber`, добавьте `*args` в сигнатуру:831832```python833>>> class AutoNumber(NoValue):834...     def __new__(cls, *args):      # это единственное изменение по сравнению с предыдущим835...         value = len(cls.__members__) + 1836...         obj = object.__new__(cls)837...         obj._value_ = value838...         return obj839...840```841842Затем при наследовании от `AutoNumber` можно написать собственный `__init__` для обработки любых дополнительных аргументов:843844```python845>>> class Swatch(AutoNumber):846...     def __init__(self, pantone='unknown'):847...         self.pantone = pantone848...     AUBURN = '3497'849...     SEA_GREEN = '1246'850...     BLEACHED_CORAL = () # Новый цвет, кода Pantone пока нет!851...852>>> Swatch.SEA_GREEN853<Swatch.SEA_GREEN: 2>854>>> Swatch.SEA_GREEN.pantone855'1246'856>>> Swatch.BLEACHED_CORAL.pantone857'unknown'858```859860> **Примечание**861>862> Метод [`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__), если он определён, используется во время создания членов Enum; затем он заменяется методом [`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__) класса Enum, который используется после создания класса для поиска существующих членов.863864### OrderedEnum865866Упорядоченное перечисление, которое не основано на [`IntEnum`](https://python-all.ru/3.8/library/enum.html#enum.IntEnum) и поэтому сохраняет обычные инварианты [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) (например, несравнимость с другими перечислениями):867868```python869>>> class OrderedEnum(Enum):870...     def __ge__(self, other):871...         if self.__class__ is other.__class__:872...             return self.value >= other.value873...         return NotImplemented874...     def __gt__(self, other):875...         if self.__class__ is other.__class__:876...             return self.value > other.value877...         return NotImplemented878...     def __le__(self, other):879...         if self.__class__ is other.__class__:880...             return self.value <= other.value881...         return NotImplemented882...     def __lt__(self, other):883...         if self.__class__ is other.__class__:884...             return self.value < other.value885...         return NotImplemented886...887>>> class Grade(OrderedEnum):888...     A = 5889...     B = 4890...     C = 3891...     D = 2892...     F = 1893...894>>> Grade.C < Grade.A895True896```897898### DuplicateFreeEnum899900Вызывает ошибку, если обнаружено дублирующееся имя члена, вместо создания псевдонима:901902```python903>>> class DuplicateFreeEnum(Enum):904...     def __init__(self, *args):905...         cls = self.__class__906...         if any(self.value == e.value for e in cls):907...             a = self.name908...             e = cls(self.value).name909...             raise ValueError(910...                 "aliases not allowed in DuplicateFreeEnum:  %r --> %r"911...                 % (a, e))912...913>>> class Color(DuplicateFreeEnum):914...     RED = 1915...     GREEN = 2916...     BLUE = 3917...     GRENE = 2918...919Traceback (most recent call last):920...921ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'922```923924> **Примечание**925>926> Это полезный пример подкласса Enum для добавления или изменения другого поведения, а также запрета псевдонимов. Если требуется только запрет псевдонимов, вместо этого можно использовать декоратор [`unique()`](https://python-all.ru/3.8/library/enum.html#enum.unique).927928### Planet929930Если определены [`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__) или [`__init__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__init__), значение члена перечисления будет передано этим методам:931932```python933>>> class Planet(Enum):934...     MERCURY = (3.303e+23, 2.4397e6)935...     VENUS   = (4.869e+24, 6.0518e6)936...     EARTH   = (5.976e+24, 6.37814e6)937...     MARS    = (6.421e+23, 3.3972e6)938...     JUPITER = (1.9e+27,   7.1492e7)939...     SATURN  = (5.688e+26, 6.0268e7)940...     URANUS  = (8.686e+25, 2.5559e7)941...     NEPTUNE = (1.024e+26, 2.4746e7)942...     def __init__(self, mass, radius):943...         self.mass = mass       # в килограммах944...         self.radius = radius   # в метрах945...     @property946...     def surface_gravity(self):947...         # гравитационная постоянная (м3 кг-1 с-2)948...         G = 6.67300E-11949...         return G * self.mass / (self.radius * self.radius)950...951>>> Planet.EARTH.value952(5.976e+24, 6378140.0)953>>> Planet.EARTH.surface_gravity9549.802652743337129955```956957### TimePeriod958959Пример использования атрибута `_ignore_`:960961```python962>>> from datetime import timedelta963>>> class Period(timedelta, Enum):964...     "different lengths of time"965...     _ignore_ = 'Period i'966...     Period = vars()967...     for i in range(367):968...         Period['day_%d' % i] = i969...970>>> list(Period)[:2]971[<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]972>>> list(Period)[-2:]973[<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]974```975976## Чем перечисления отличаются?977978Перечисления имеют собственный метакласс, который влияет на многие аспекты как производных классов Enum, так и их экземпляров (членов).979980### Классы Enum981982Метакласс `EnumMeta` отвечает за предоставление методов [`__contains__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__contains__), [`__dir__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__dir__), [`__iter__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__iter__) и других, которые позволяют выполнять с классом [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) действия, невозможные для обычного класса, например *list(Color)* или *some\_enum\_var in Color*. `EnumMeta` отвечает за то, чтобы различные другие методы конечного класса [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) были корректны (такие как [`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__), [`__getnewargs__()`](https://python-all.ru/3.8/library/pickle.html#object.__getnewargs__), [`__str__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__str__) и [`__repr__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__repr__)).983984### Элементы Enum (также известные как экземпляры)985986Самое интересное в членах Enum – это то, что они являются синглтонами. `EnumMeta` создаёт их все при создании самого класса [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum), а затем помещает на место настраиваемый [`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__), чтобы гарантировать, что новые экземпляры никогда не будут созданы, возвращая только существующие экземпляры членов.987988### Тонкие моменты989990#### Поддерживаемые `__dunder__` имена991992`__members__` представляет собой упорядоченное отображение только для чтения элементов `member_name`:`member`. Оно доступно только на уровне класса.993994[`__new__()`](https://python-all.ru/3.8/reference/datamodel.html#object.__new__), если указан, должен создавать и возвращать элементы перечисления; также рекомендуется соответствующим образом установить `_value_` элемента. После создания всех элементов он больше не используется.995996#### Поддерживаемые `_sunder_` имена997998- `_name_` – имя члена999- `_value_` – значение элемента; может быть установлено / изменено в `__new__`1000- `_missing_` – функция поиска, используемая, когда значение не найдено; может быть переопределена1001- `_ignore_` – список имён, либо в виде [`list()`](https://python-all.ru/3.8/library/stdtypes.html#list), либо [`str()`](https://python-all.ru/3.8/library/stdtypes.html#str), которые не будут преобразованы в элементы и будут удалены из итогового класса1002- `_order_` – используется в коде для Python 2/3 для обеспечения согласованности порядка элементов (атрибут класса, удаляется при создании класса)1003- `_generate_next_value_` – используется [функциональным API](https://python-all.ru/3.8/library/enum.html#functional-api) и [`auto`](https://python-all.ru/3.8/library/enum.html#enum.auto) для получения подходящего значения для элемента перечисления; может быть переопределён10041005Новое в версии 3.6: `_missing_`, `_order_`, `_generate_next_value_`10061007Новое в версии 3.7: `_ignore_`10081009Чтобы помочь синхронизировать код Python 2 и Python 3, можно указать атрибут `_order_`. Он будет проверен на соответствие фактическому порядку перечисления, и если они не совпадают, будет вызвана ошибка:10101011```python1012>>> class Color(Enum):1013...     _order_ = 'RED GREEN BLUE'1014...     RED = 11015...     BLUE = 31016...     GREEN = 21017...1018Traceback (most recent call last):1019...1020TypeError: member order does not match _order_1021```10221023> **Примечание**1024>1025> В коде Python 2 атрибут `_order_` необходим, поскольку порядок определения теряется до того, как его можно зафиксировать.10261027#### Тип члена `Enum`10281029Члены [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) являются экземплярами своего класса [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) и обычно доступны как `EnumClass.member`. При определённых обстоятельствах к ним также можно обращаться как `EnumClass.member.member`, но никогда не следует этого делать, так как такой поиск может завершиться неудачей или, что ещё хуже, вернуть что-то кроме искомого члена [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) (это ещё одна веская причина использовать для членов имена в верхнем регистре):10301031```python1032>>> class FieldTypes(Enum):1033...     name = 01034...     value = 11035...     size = 21036...1037>>> FieldTypes.value.size1038<FieldTypes.size: 2>1039>>> FieldTypes.size.value104021041```10421043Изменено в версии 3.5.10441045#### Логическое значение классов и членов `Enum`10461047Члены [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum), смешанные с не-[`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) типами (такими как [`int`](https://python-all.ru/3.8/library/functions.html#int), [`str`](https://python-all.ru/3.8/library/stdtypes.html#str) и т.п.), вычисляются по правилам примешанного типа; в противном случае все члены вычисляются как [`True`](https://python-all.ru/3.8/library/constants.html#True). Чтобы логическое вычисление вашего собственного Enum зависело от значения члена, добавьте в свой класс следующее:10481049```python1050def __bool__(self):1051    return bool(self.value)1052```10531054Классы [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) всегда вычисляются как [`True`](https://python-all.ru/3.8/library/constants.html#True).10551056#### `Enum` классы с методами10571058Если добавить подклассу [`Enum`](https://python-all.ru/3.8/library/enum.html#enum.Enum) дополнительные методы, как в классе [Planet](https://python-all.ru/3.8/library/enum.html#planet) выше, эти методы будут видны в [`dir()`](https://python-all.ru/3.8/library/functions.html#dir) члена, но не класса:10591060```python1061>>> dir(Planet)1062['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__members__', '__module__']1063>>> dir(Planet.EARTH)1064['__class__', '__doc__', '__module__', 'name', 'surface_gravity', 'value']1065```10661067#### Объединение элементов `Flag`10681069Если комбинация членов Flag не имеет имени, [`repr()`](https://python-all.ru/3.8/library/functions.html#repr) будет включать все именованные флаги и все именованные комбинации флагов, присутствующие в значении:10701071```python1072>>> class Color(Flag):1073...     RED = auto()1074...     GREEN = auto()1075...     BLUE = auto()1076...     MAGENTA = RED | BLUE1077...     YELLOW = RED | GREEN1078...     CYAN = GREEN | BLUE1079...1080>>> Color(3)  # именованная комбинация1081<Color.YELLOW: 3>1082>>> Color(7)      # не именованная комбинация1083<Color.CYAN|MAGENTA|BLUE|YELLOW|GREEN|RED: 7>1084```1085