Enum python что это

Enum в Python

В большинстве современных языках программирования поддерживается работа с перечислениями и Python – не исключение. Программист может обойтись без них. Однако, как и многие другие инструменты, перечисления в Python упрощают написание и редактирования кода.

Что такое enum в Python

Enum — это один из модулей языка Python, с английского дословно переводится, как перечисление, что полностью отражает суть модуля.

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

Подключение

Модуль enum является частью стандартной библиотеки Python 3, поэтому его не нужно отдельно устанавливать, достаточно подключить нужный класс с помощью команды import:

Если по какой-то причине интерпретатор Python не может найти модуль enum, установите его с помощью команды:

Создание

Перечисления создаются с использованием синтаксиса классов. Это упрощает их чтение и написание. Пример:

В результате мы получим следующее:

Значение элементов могут быть представлены любыми типами (str, int и другие). Структура перечисления следующая:

Программист может не прописывать значения элементов, вместо этого он может использовать функцию auto(), которая автоматически присваивает элементу значение «1», а каждому последующему — значение на единицу больше:

Свойства

Поддержка итераций

Перечисления — это итерируемые объекты, это значит, что все элементы можно перебрать в цикле. Пример:

В результате выполнение в консоль выведется:

Понятная человеку семантика

Одна из причин, почему программисты предпочитают перечисления массивам, заключается в понятности.

Тип элемента перечисления — это перечисление

Хэшируемость

Элементы перечисления хэшируемые. То есть программист может использовать их в словарях и множествах. Вспомним, что хэш позволяет создавать высокопроизводительные структуры, используя хэш-функции для сокращения объема данных.

Создание методов

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

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

Распространённые ошибки

Работая с перечислениями программист может допустить следующие ошибки:

Источник

enum — Support for enumerations¶

Source code: Lib/enum.py

An enumeration is a set of symbolic names (members) bound to unique, constant values. Within an enumeration, the members can be compared by identity, and the enumeration itself can be iterated over.

Case of Enum Members

Because Enums are used to represent constants we recommend using UPPER_CASE names for enum members, and will be using that style in our examples.

Module ContentsВ¶

Base class for creating enumerated constants. See section Functional API for an alternate construction syntax.

class enum. IntEnum В¶

class enum. IntFlag В¶

Base class for creating enumerated constants that can be combined using the bitwise operations without losing their Flag membership.

Enum class decorator that ensures only one name is bound to any one value.

Instances are replaced with an appropriate value for Enum members. By default, the initial value starts at 1.

Creating an EnumВ¶

Enumerations are created using the class syntax, which makes them easy to read and write. An alternative creation method is described in Functional API. To define an enumeration, subclass Enum as follows:

Enum member values

The class Color is an enumeration (or enum)

Even though we use the class syntax to create Enums, Enums are not normal Python classes. See How are Enums different? for more details.

Enumeration members have human readable string representations:

…while their repr has more information:

The type of an enumeration member is the enumeration it belongs to:

Enum members also have a property that contains just their item name:

Enumerations support iteration, in definition order:

Enumeration members are hashable, so they can be used in dictionaries and sets:

Programmatic access to enumeration members and their attributesВ¶

Sometimes it’s useful to access members in enumerations programmatically (i.e. situations where Color.RED won’t do because the exact color is not known at program-writing time). Enum allows such access:

If you want to access enum members by name, use item access:

If you have an enum member and need its name or value :

Duplicating enum members and valuesВ¶

Having two enum members with the same name is invalid:

However, two enum members are allowed to have the same value. Given two members A and B with the same value (and A defined first), B is an alias to A. By-value lookup of the value of A and B will return A. By-name lookup of B will also return A:

Attempting to create a member with the same name as an already defined attribute (another member, a method, etc.) or attempting to create an attribute with the same name as a member is not allowed.

Ensuring unique enumeration valuesВ¶

By default, enumerations allow multiple names as aliases for the same value. When this behavior isn’t desired, the following decorator can be used to ensure each value is used only once in the enumeration:

A class decorator specifically for enumerations. It searches an enumeration’s __members__ gathering any aliases it finds; if any are found ValueError is raised with the details:

Using automatic valuesВ¶

If the exact value is unimportant you can use auto :

The goal of the default _generate_next_value_() method is to provide the next int in sequence with the last int provided, but the way it does this is an implementation detail and may change.

The _generate_next_value_() method must be defined before any members.

IterationВ¶

Iterating over the members of an enum does not provide the aliases:

The special attribute __members__ is a read-only ordered mapping of names to members. It includes all names defined in the enumeration, including the aliases:

The __members__ attribute can be used for detailed programmatic access to the enumeration members. For example, finding all the aliases:

ComparisonsВ¶

Enumeration members are compared by identity:

Ordered comparisons between enumeration values are not supported. Enum members are not integers (but see IntEnum below):

Equality comparisons are defined though:

Comparisons against non-enumeration values will always compare not equal (again, IntEnum was explicitly designed to behave differently, see below):

Allowed members and attributes of enumerationsВ¶

The examples above use integers for enumeration values. Using integers is short and handy (and provided by default by the Functional API), but not strictly enforced. In the vast majority of use-cases, one doesn’t care what the actual value of an enumeration is. But if the value is important, enumerations can have arbitrary values.

Enumerations are Python classes, and can have methods and special methods as usual. If we have this enumeration:

Note: if your enumeration defines __new__() and/or __init__() then any value(s) given to the enum member will be passed into those methods. See Planet for an example.

Restricted Enum subclassingВ¶

Also, subclassing an enumeration is allowed only if the enumeration does not define any members. So this is forbidden:

But this is allowed:

Allowing subclassing of enums that define members would lead to a violation of some important invariants of types and instances. On the other hand, it makes sense to allow sharing some common behavior between a group of enumerations. (See OrderedEnum for an example.)

PicklingВ¶

Enumerations can be pickled and unpickled:

The usual restrictions for pickling apply: picklable enums must be defined in the top level of a module, since unpickling requires them to be importable from that module.

With pickle protocol version 4 it is possible to easily pickle enums nested in other classes.

It is possible to modify how Enum members are pickled/unpickled by defining __reduce_ex__() in the enumeration class.

Functional APIВ¶

The Enum class is callable, providing the following functional API:

The second argument is the source of enumeration member names. It can be a whitespace-separated string of names, a sequence of names, a sequence of 2-tuples with key/value pairs, or a mapping (e.g. dictionary) of names to values. The last two options enable assigning arbitrary values to enumerations; the others auto-assign increasing integers starting with 1 (use the start parameter to specify a different starting value). A new class derived from Enum is returned. In other words, the above assignment to Animal is equivalent to:

Pickling enums created with the functional API can be tricky as frame stack implementation details are used to try and figure out which module the enumeration is being created in (e.g. it will fail if you use a utility function in separate module, and also may not work on IronPython or Jython). The solution is to specify the module name explicitly as follows:

If module is not supplied, and Enum cannot determine what it is, the new Enum members will not be unpicklable; to keep errors closer to the source, pickling will be disabled.

The new pickle protocol 4 also, in some circumstances, relies on __qualname__ being set to the location where pickle will be able to find the class. For example, if the class was made available in class SomeData in the global scope:

The complete signature is:

What the new Enum class will record as its name.

The Enum members. This can be a whitespace or comma separated string (values will start at 1 unless otherwise specified):

Источник

enum — Поддержка перечислений¶

Добавлено в версии 3.4.

Исходный код: Lib/enum.py

Перечисление — это множество символических имён (полей), привязанных к уникальным постоянным значениям. Внутри перечисления поля могут сравниваться по идентичности, а само перечисление может итерироваться.

Регистр полей Enum

Поскольку перечисления используются для представления констант, мы рекомендуем использовать имена полей В_ВЕРХНЕМ_РЕГИСТРЕ для перечисления и будем использовать этот стиль в наших примерах.

Содержание модуля¶

Базовый класс для создания перечисляемых констант. Альтернативный синтаксис построения см. в разделе Функциональный API.

class enum. IntEnum ¶

class enum. IntFlag ¶

Декоратор класса Enum, который обеспечивает привязку только одного имени к любому значению.

Экземпляры заменяются соответствующим значением для полей Enum. Начальное значение начинается с 1.

Создание Enum¶

Перечисление значений поля

Поля перечисления содержат человекочитаемое строковое представление:

… в то время как их repr возвращает больше информации:

type поле перечисления является перечислением, которому оно принадлежит:

У полей перечисления также есть свойство, которое содержит только их имя элемента:

Перечисления поддерживают итерацию в порядке определения:

Поля перечисления хэшируемы, поэтому они могут использоваться в словарях и множествах:

Программный доступ к полям перечисления и их атрибутам¶

Иногда бывает полезно получить доступ к полям в перечислениях программно (например, в ситуациях, когда Color.RED не подходит, потому что точный цвет неизвестен во время написания программы). Enum разрешает такой доступ:

Если вы хотите получить доступ к полям перечисления по имени, используйте доступ к элементам:

Если у вас есть поле перечисления и вам нужно его name или value :

Дублирование enum полей и значений¶

Наличие двух полей перечисления с одинаковым именем недопустимо:

Однако два поля перечисления могут содержать одинаковое значение. Для двух полей A и B с одинаковым значением (и A, определенного первым), B является псевдонимом для A. Поиск по значению значений A и B вернёт A. Поиск по имени B также вернёт A:

Попытки создать поля с тем же именем, что с уже определенным атрибутом (другим полем, методом и т. д.) или попытка создать атрибут с тем же именем, что и поле, не разрешены.

Обеспечение уникальных значений перечисления¶

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

Декоратор class специально для перечислений. Он ищет в __members__ перечисления, собирая все найденные псевдонимы; если таковые найдены, то поднимается ValueError с подробностями:

Использование автоматических значений¶

Если точное значение неважно, можно использовать auto :

Метод _generate_next_value_() должен быть определен перед любыми полями.

Итерация¶

Итерация по элементам перечисления не предоставляет псевдонимов:

Специальный атрибут __members__ представляет собой упорядоченное отображение имён полей только для чтения. Он включает все имена, определенные в перечислении, включая псевдонимы:

Атрибут __members__ может использоваться для подробного программного доступа к полям перечисления. Например, поиск всех псевдонимов:

Сравнения¶

Поля перечисления сравниваются по идентификатору:

Упорядоченные сравнения значения перечисления не поддерживаются. Поля Enum не целые числа (но см. IntEnum ниже):

Несмотря на то, что сравнения на равенство:

Сравнения с неперечисляемыми значениями всегда будут сравниваться не равными (опять же, IntEnum был явно разработан, чтобы вести себя по-другому, см. ниже):

Допустимые поля и атрибуты перечислений¶

В приведенных выше примерах для значений перечисления использовались целые числа. Использование целых чисел является коротким и удобным (и предоставляется по умолчанию Функциональный API), но не строго соблюдается. В подавляющем большинстве случаев использования не важно, какова фактическое значение перечисления. Но если значение является важным, перечисления могут содержать произвольные значения.

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

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

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

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

Пиклинг¶

Перечисления могут быть пиклены (pickled) и анпиклены (unpickled):

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

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

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

Функциональный API¶

Класс Enum является вызываемым, предоставляя следующий функциональный API:

Пиклинг перечислений, созданных с помощью функционального API, может быть сложным, поскольку используются детали реализации стека фреймов, чтобы попытаться выяснить, в каком модуле создаётся перечисление (например, не удастся, если вы используете служебную функцию в отдельном модуле, и также может не работать на IronPython или Jython). Решение состоит в том, чтобы явно указать имя модуля следующим образом:

Если module не предоставлен, и Enum не может определить, что это такое, новые поля Enum не будут анпиклены; чтобы ошибки были ближе к источнику, пиклинг будет отключено.

Полная сигнатура следующая:

Что новый класс Enum запишет в качестве своего названия.

поля Enum. Это может быть пробел или разделенное запятыми строка (значения начинается с 1, если не указано иное):

или итератор пар (имя, значение):

имя модуля, где можно найти новый класс Enum.

где в модуле можно найти новый класс Enum.

тип, чтобы смешать с новым классом Enum.

число для начала подсчета, если будут переданы только имена.

Изменено в версии 3.5: добавлен Был добавлен параметр start.

Производные перечисления¶

IntEnum¶

Однако они всё ещё не могут сравниться со стандартными перечислениями Enum :

Значения IntEnum ведут себя как целые числа в других отношениях, которые вы ожидаете:

IntFlag¶

Добавлено в версии 3.6.

Также можно назвать комбинации:

Другое важное отличие между IntFlag и Enum состоит в том, что если флаги не установлены (значение равно 0), его логическая оценка является False :

Добавлено в версии 3.6.

Отдельные флаги должны содержать значения, являющиеся степенями двойки (1, 2, 4, 8, …), а комбинации флагов — нет:

Присвоение имени условию «флаги не установлены» не изменяет его логическое значение:

Другие¶

Когда использовать __new__() против __init__() ¶

Например, если вы хотите передать конструктору несколько элементов, но только один из них должен быть значением:

Интересные примеры¶

Пропуск значений¶

Во многих случаях использования не важно, каково фактическое значение перечисления. Существует несколько способов определения простого типа перечисления:

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

Источник

Быстрый ENUM

Зачем нужно перечисление (enum)

(если вы все знаете — опуститесь до секции «Перечисления в стандартной библиотеке»)

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

… или как статические атрибуты класса:

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

Или же ваш класс становится таким:

Наконец, именованный кортеж превращается в:

Уже неплохо — теперь он гарантирует, что и значение состояния и заглушка перевода отображаются на языки поддерживаемые UI. Но вы можете заметить, что код, использующий эти отображения, превратился в бардак. Каждый раз, пытаясь присвоить значение сущности, приходится извлекать значение с индексом 0 из используемого вами отображения:

илиили
И так далее. Помните, что первые два подхода, использующие константы и атрибуты класса, соответственно, страдают от изменяемости.

И вот перечисления приходят к нам на помощь

Вот и все. Теперь вы можете легко перебирать перечисление в вашем рендере (синтаксис Jinja2):

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

В вашем коде вы просто присваиваете значения вашим сущностям, вот так:

Все достаточно понятно, информативно и расширяемо. Вот для чего мы используем перечисления.

Как мы смогли сделать его быстрее?

Перечисление из стандартной библиотеки довольно медленное, поэтому мы спросили себя — можем ли мы ускорить его? Как оказалось — можем, а именно, реализация нашего перечисления:

Slots

К примеру, можно использовать объявление класса с помощью __slots__ — в этом случае все экземпляры классов будут иметь только ограниченный набор свойств, объявленных в __slots__ и всех __slots__ родительских классов.

Descriptors

По умолчанию интерпретатор Python возвращает значение атрибута объекта напрямую (при этом оговоримся, что в данном случае значение — это тоже объект Python, а не, например, unsigned long long в терминах языка Си):
value = my_obj.attribute # это прямой доступ к значению атрибута по указателю, который объект хранит для этого атрибута.

Перечисления в стандартной библиотеке

Таким образом, вся последовательность вызовов может быть представлена следующими псевдокодом:

Мы написали простой скрипт демонстрирующий вывод, описанный выше:

И после выполнения скрипт выдал нам следующую картинку:
Enum python что это. Смотреть фото Enum python что это. Смотреть картинку Enum python что это. Картинка про Enum python что это. Фото Enum python что это

Сравните с нашим FastEnum:

Что видно на следующем изображении:
Enum python что это. Смотреть фото Enum python что это. Смотреть картинку Enum python что это. Картинка про Enum python что это. Фото Enum python что это

Все это действительно происходит внутри стандартной реализации перечислений каждый раз, когда вы обращаетесь к свойствам name и value их членов. Это же и причина, по которой наша реализация быстрее.

Наш подход

Свою реализацию перечислений мы создавали с оглядкой на элегантные перечисления в C и прекрасные расширяемые перечисления в Java. Основные функции, которые мы хотели реализовать у себя, были следующими:

Каковы дополнительные фишки?

FastEnum не совместим ни с какой версией Python до 3.6, поскольку повсеместно использует аннотации типов, внедренные в Python 3.6. Можно предположить, что установка модуля typing из PyPi поможет. Краткий ответ — нет. Реализация использует PEP-484 для аргументов некоторых функций, методов и указателей на тип возвращаемого значения, поэтому любая версия до Python 3.5 не поддерживается из-за несовместимости синтаксиса. Но, опять же, самая первая строка кода в __new__ метакласса использует синтаксис PEP-526 для указания типа переменной. Так что Python 3.5 тоже не подойдет. Можно перенести реализацию на более старые версии, хотя мы в Qrator Labs, как правило, используем аннотации типов когда это возможно, так как это сильно помогает в разработке сложных проектов. Ну и в конце-концов! Вы же не хотите застрять в Python до версии 3.6, поскольку в более новых версиях нет обратной несовместимости с вашим существующим кодом (при условии, что вы не используете Python 2), а ведь в реализации asyncio была проделана большая работа по сравнению с 3.5, на наш взгляд, стоящая незамедлительного обновления.

Однако, существуют некоторые ограничения: все имена членов перечисления должны быть написаны ЗАГЛАВНЫМИ буквами, иначе они не будут обработаны метаклассом.

Наконец, вы можете объявить базовый класс для ваших перечислений (имейте в виду, что базовый класс может сам использовать метакласс, поэтому вам не нужно предоставлять метакласс всем подклассам) — достаточно определить общую логику (атрибуты и методы) в этом классе и не определять членов перечисления (так что класс не будет «финализирован»). После можно объявить столько наследующих классов этого класса, сколько захотите, а сами наследники при этом будут иметь общую логику.

Псевдонимы и как они могут помочь

Предположим, что у вас есть код, использующий:

И что класс MyEnum объявлен следующим образом:

Теперь, вы решили что хотите сделать кое-какой рефакторинг и перенести перечисление в другой пакет. Вы создаете что-то вроде этого:

Где MyMovedEnum объявлен так:

Вот и все. При перезапуске ваших приложений на этапе unpickle все члены перечисления будут переобъявлены как экземпляры MyMovedEnum и станут связаны с этим новым классом. В тот момент, когда вы будете уверены, что все ваши хранимые, например, в базе данных, объекты были повторно десериализованы (и, возможно, сериализованы опять и сохранены в хранилище) — вы можете выпустить новый релиз, в котором ранее помеченный как устаревший класс MyEnum может быть объявлен более ненужным и удаленным из кодовой базы.

Источник

Гайд по использованию enum в Python

Enum python что это. Смотреть фото Enum python что это. Смотреть картинку Enum python что это. Картинка про Enum python что это. Фото Enum python что это

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

Создание

Итерирование

При итерировании по классу вы пройдёте по атрибутам.

Цикл будет идти по элементам в том порядке, в котором они указаны при создании класса. Названия и значения никак не влияют на порядок.

Сравнение перечислений

Так как элементы перечислений не упорядочены, то они поддерживают сравнение только по названию или значению.

IntEnum

Уникальные значения в перечислениях

Элементы перечисления с одинаковыми значениями являются несколькими названиями, указывающими на один и тот же объект.

Так как by_design и closed являются синонимами для других элементов, то они не появляются как элементы в циклах. Истинным считается название, указанное первым при объявлении.

Если вы хотите, чтобы все элементы обязательно имели разные значения, то добавьте декоратор @unique перед объявлением класса.

Элементы с повторяющимися значениями будут вызывать ValueError во время интерпретации.

Другой способ создания перечислений

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

Аргумент value является названием перечисления, которое используется для создания представления элементов. Второй аргумент names принимает список названий в перечислении. Если подать одну строку, то она будет разбита по пробельным символам и запятым, а значения будут числами, начиная с 1.

Также аргумент name принимает список пар названиезначение, либо аналогичный словарь.

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

Другие типы значений

В этом примере каждое значение является парой из числового id и списка строк, описывающих возможный переход из данного состояния.

Данный пример аналогичен предыдущему, но в нём используются словари вместо tuple для удобства.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *