Python Enum — перечисления в Python

17 июля 2026
Автор

Антон Ларичев

Что такое Enum в Python

Enum (перечисление) — это специальный тип данных, позволяющий задать набор именованных констант. Модуль enum появился в стандартной библиотеке Python начиная с версии 3.4 и решает одну из частых задач: хранить фиксированный набор значений с понятными именами.

Без перечислений разработчики нередко прибегают к «магическим числам» или строкам:

# Плохой подход — «магические» константы
STATUS_ACTIVE = 1
STATUS_INACTIVE = 2
STATUS_BANNED = 3

def get_user_status(status):
    if status == 1:
        return "Активен"
    elif status == 2:
        return "Неактивен"

Такой код трудно читать, легко сделать опечатку и сложно рефакторить. Enum решает эти проблемы.

Создание простого перечисления

Для создания перечисления нужно импортировать Enum из модуля enum и унаследоваться от него:

from enum import Enum

class UserStatus(Enum):
    ACTIVE = 1
    INACTIVE = 2
    BANNED = 3

Теперь можно обращаться к членам перечисления через имя класса:

status = UserStatus.ACTIVE
print(status)        # UserStatus.ACTIVE
print(status.name)   # ACTIVE
print(status.value)  # 1
print(type(status))  # <enum 'UserStatus'>

Каждый член перечисления — это экземпляр класса UserStatus, а не просто число или строка.

Перебор членов перечисления

Enum поддерживает итерацию — можно перебрать все значения в цикле:

for status in UserStatus:
    print(f"{status.name}: {status.value}")

# ACTIVE: 1
# INACTIVE: 2
# BANNED: 3

Чтобы получить список всех членов:

all_statuses = list(UserStatus)
print(all_statuses)
# [<UserStatus.ACTIVE: 1>, <UserStatus.INACTIVE: 2>, <UserStatus.BANNED: 3>]

Доступ к членам перечисления

Sуществует несколько способов получить конкретный член:

# По имени
status = UserStatus['ACTIVE']
print(status)  # UserStatus.ACTIVE

# По значению
status = UserStatus(2)
print(status)  # UserStatus.INACTIVE

# По атрибуту
status = UserStatus.BANNED
print(status)  # UserStatus.BANNED

Если передать несуществующее значение, Python выбросит исключение:

try:
    status = UserStatus(99)
except ValueError as e:
    print(e)  # 99 is not a valid UserStatus

Сравнение членов перечисления

Члены одного перечисления можно сравнивать на равенство и идентичность:

status = UserStatus.ACTIVE

print(status == UserStatus.ACTIVE)    # True
print(status == UserStatus.INACTIVE)  # False
print(status is UserStatus.ACTIVE)    # True

Важный момент: члены Enum не сравниваются с обычными числами по умолчанию:

print(UserStatus.ACTIVE == 1)  # False

Это намеренное поведение, защищающее от случайных сравнений с «магическими» числами.

Строковые перечисления

Значениями членов могут быть строки — это удобно для хранения состояний в базе данных или передачи через API:

from enum import Enum

class Direction(Enum):
    NORTH = "north"
    SOUTH = "south"
    EAST = "east"
    WEST = "west"

current = Direction.NORTH
print(current.value)  # north

StrEnum — автоматическое сравнение со строками

Начиная с Python 3.11 доступен StrEnum. Его члены ведут себя как строки:

from enum import StrEnum

class Color(StrEnum):
    RED = "red"
    GREEN = "green"
    BLUE = "blue"

print(Color.RED == "red")  # True
print(f"Цвет: {Color.GREEN}")  # Цвет: green

IntEnum — сравнение с числами

IntEnum позволяет сравнивать члены перечисления с обычными целыми числами:

from enum import IntEnum

class Priority(IntEnum):
    LOW = 1
    MEDIUM = 2
    HIGH = 3
    CRITICAL = 4

print(Priority.HIGH > Priority.LOW)  # True
print(Priority.MEDIUM == 2)          # True
print(sorted([Priority.HIGH, Priority.LOW, Priority.CRITICAL]))
# [<Priority.LOW: 1>, <Priority.HIGH: 3>, <Priority.CRITICAL: 4>]

Однако злоупотреблять IntEnum не стоит: потеря строгости типов может привести к трудноуловимым ошибкам.

auto() — автоматическая нумерация

Функция auto() позволяет не задавать значения вручную — Python присвоит их автоматически:

from enum import Enum, auto

class Season(Enum):
    SPRING = auto()
    SUMMER = auto()
    AUTUMN = auto()
    WINTER = auto()

for season in Season:
    print(f"{season.name}: {season.value}")

# SPRING: 1
# SUMMER: 2
# AUTUMN: 3
# WINTER: 4

По умолчанию auto() начинает с 1 и увеличивает на 1. Поведение можно переопределить через метод _generate_next_value_:

from enum import Enum, auto

class LowercaseEnum(Enum):
    @staticmethod
    def _generate_next_value_(name, start, count, last_values):
        return name.lower()

class HttpMethod(LowercaseEnum):
    GET = auto()
    POST = auto()
    PUT = auto()
    DELETE = auto()

print(HttpMethod.GET.value)     # get
print(HttpMethod.DELETE.value)  # delete

Flag — битовые флаги

Flag предназначен для создания флагов, которые можно комбинировать с помощью побитовых операций:

from enum import Flag, auto

class Permission(Flag):
    READ = auto()
    WRITE = auto()
    EXECUTE = auto()
    ADMIN = READ | WRITE | EXECUTE

# Комбинирование флагов
user_permissions = Permission.READ | Permission.WRITE
print(user_permissions)  # Permission.READ|WRITE

# Проверка флага
print(Permission.READ in user_permissions)   # True
print(Permission.EXECUTE in user_permissions) # False

# Права администратора
admin = Permission.ADMIN
print(Permission.WRITE in admin)  # True

IntFlag работает аналогично, но совместим с обычными целыми числами:

from enum import IntFlag

class FileMode(IntFlag):
    NONE = 0
    READ = 4
    WRITE = 2
    EXECUTE = 1

mode = FileMode.READ | FileMode.WRITE
print(mode)        # FileMode.READ|WRITE
print(int(mode))   # 6
print(mode & 4)    # FileMode.READ (битовое AND)

Методы и свойства в Enum

В перечисления можно добавлять методы, что делает их полноценными объектами с поведением:

from enum import Enum

class Planet(Enum):
    MERCURY = (3.303e+23, 2.4397e6)
    VENUS   = (4.869e+24, 6.0518e6)
    EARTH   = (5.976e+24, 6.37814e6)
    MARS    = (6.421e+23, 3.3972e6)

    def __init__(self, mass, radius):
        self.mass = mass      # кг
        self.radius = radius  # метры

    @property
    def surface_gravity(self):
        G = 6.67430e-11
        return G * self.mass / (self.radius ** 2)

    def weight(self, mass_on_earth):
        return mass_on_earth * self.surface_gravity / Planet.EARTH.surface_gravity

print(f"Ускорение на Марсе: {Planet.MARS.surface_gravity:.2f} м/с²")
# Ускорение на Марсе: 3.71 м/с²

print(f"Вес 75 кг на Марсе: {Planet.MARS.weight(75):.1f} кг")
# Вес 75 кг на Марсе: 28.5 кг

Псевдонимы в перечислениях

Если два члена имеют одинаковое значение, второй становится псевдонимом первого:

from enum import Enum

class Color(Enum):
    RED = 1
    CRIMSON = 1   # псевдоним для RED
    GREEN = 2
    BLUE = 3

print(Color.CRIMSON)          # Color.RED
print(Color.CRIMSON is Color.RED)  # True

# Псевдонимы не попадают в итерацию
for color in Color:
    print(color)
# Color.RED
# Color.GREEN
# Color.BLUE

Чтобы запретить псевдонимы, используйте декоратор @unique:

from enum import Enum, unique

@unique
class Color(Enum):
    RED = 1
    CRIMSON = 1  # ValueError: duplicate values found

Практический пример: состояния заказа

Рассмотрим реальный сценарий — управление состояниями заказа в интернет-магазине:

from enum import Enum, auto
from datetime import datetime

class OrderStatus(Enum):
    PENDING = auto()
    CONFIRMED = auto()
    SHIPPED = auto()
    DELIVERED = auto()
    CANCELLED = auto()

    def can_cancel(self) -> bool:
        return self in (OrderStatus.PENDING, OrderStatus.CONFIRMED)

    def next_status(self):
        transitions = {
            OrderStatus.PENDING: OrderStatus.CONFIRMED,
            OrderStatus.CONFIRMED: OrderStatus.SHIPPED,
            OrderStatus.SHIPPED: OrderStatus.DELIVERED,
        }
        return transitions.get(self)

class Order:
    def __init__(self, order_id: int):
        self.order_id = order_id
        self.status = OrderStatus.PENDING
        self.history = [(self.status, datetime.now())]

    def advance(self):
        next_s = self.status.next_status()
        if next_s is None:
            raise ValueError(f"Нельзя перевести из статуса {self.status.name}")
        self.status = next_s
        self.history.append((self.status, datetime.now()))

    def cancel(self):
        if not self.status.can_cancel():
            raise ValueError(f"Нельзя отменить заказ со статусом {self.status.name}")
        self.status = OrderStatus.CANCELLED
        self.history.append((self.status, datetime.now()))

# Использование
order = Order(order_id=42)
print(order.status)  # OrderStatus.PENDING

order.advance()
print(order.status)  # OrderStatus.CONFIRMED

order.advance()
print(order.status)  # OrderStatus.SHIPPED

try:
    order.cancel()  # Нельзя отменить — заказ уже отправлен
except ValueError as e:
    print(e)  # Нельзя отменить заказ со статусом SHIPPED

Сериализация и десериализация

При работе с API или базами данных часто нужно преобразовывать Enum в примитивы и обратно:

import json
from enum import Enum

class Role(Enum):
    USER = "user"
    MODERATOR = "moderator"
    ADMIN = "admin"

# Сериализация
data = {
    "username": "ivan",
    "role": Role.ADMIN.value  # "admin"
}
print(json.dumps(data))  # {"username": "ivan", "role": "admin"}

# Десериализация
raw = '{"username": "ivan", "role": "admin"}'
parsed = json.loads(raw)
role = Role(parsed["role"])
print(role)         # Role.ADMIN
print(role.name)    # ADMIN

Enum и аннотации типов

Enum хорошо интегрируется с системой типов Python:

from enum import Enum
from typing import Optional

class LogLevel(Enum):
    DEBUG = 10
    INFO = 20
    WARNING = 30
    ERROR = 40
    CRITICAL = 50

def log_message(message: str, level: LogLevel = LogLevel.INFO) -> None:
    print(f"[{level.name}] {message}")

def find_level(value: int) -> Optional[LogLevel]:
    try:
        return LogLevel(value)
    except ValueError:
        return None

log_message("Сервер запущен")                  # [INFO] Сервер запущен
log_message("Ошибка подключения", LogLevel.ERROR)  # [ERROR] Ошибка подключения

result = find_level(30)
print(result)  # LogLevel.WARNING

Частые ошибки при работе с Enum

Ошибка 1: попытка изменить значение члена перечисления.

class Status(Enum):
    ACTIVE = 1

# AttributeError — члены Enum неизменяемы
Status.ACTIVE = 2

Ошибка 2: сравнение с int без IntEnum.

class Status(Enum):
    ACTIVE = 1

print(Status.ACTIVE == 1)  # False, не True!
# Используйте Status.ACTIVE.value == 1 или IntEnum

Ошибка 3: создание экземпляра перечисления через несуществующее значение без обработки ошибки.

class Status(Enum):
    ACTIVE = 1

# Всегда оборачивайте в try/except при работе с внешними данными
try:
    s = Status(99)
except ValueError:
    s = Status.ACTIVE  # fallback

Итог

Модуль enum — мощный инструмент Python для работы с фиксированными наборами значений. Основные возможности:

  • Enum — базовый класс для перечислений с любыми значениями
  • IntEnum и StrEnum — совместимы с числами и строками соответственно
  • Flag и IntFlag — для комбинирования через побитовые операции
  • auto() — автоматическая генерация значений
  • @unique — защита от дублирующихся значений
  • Возможность добавлять методы и свойства прямо в перечисление

Использование Enum делает код более читаемым, самодокументируемым и защищённым от ошибок по сравнению с «магическими» числами и строками.

Чтобы глубже освоить Python и научиться писать чистый, профессиональный код, приходите на курс Python для разработчиков на PurpleSchool.

Стрелочка влевоАннотации типов (Type Hints) в Python

Постройте личный план изучения Python до уровня Middle — бесплатно!

Python — часть карты развития Backend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Все гайды по Python

Как отправлять запросы с помощью requests в PythonПочему Python выводит значение без команды printКак работает команда print в PythonВозможности Python для автоматизации задачРабота с JSON в Python на примерахPython get — методы получения данныхКак находить и исправлять ошибки в PythonСтруктура и оформление кода PythonРабота с данными через API и внешние сервисыОсновы Django с PythonПолезные приёмы в Python для повседневной работыИспользование locals в Python для отладкиИнтеграция PHP и PythonКак выполнять HTTPS-запросы в PythonFastAPI Python — быстрый старт: создание REST API с нуляКак работать с API в Python
Ввод целого числа в PythonВедение логов в PythonУдаление данных в Python с помощью removeОбработка исключений с помощью try/except в PythonФункция super() в Python — как вызвать метод родителяСоздание собственных контекстных менеджеров в PythonРабота с символами программирования PythonРабота с переменной X в PythonРабота с классами в PythonКак скачать Python на компьютерПростая программа на Python для начинающихОсновы Python для тех, кто начинаетЧто нового в Python 3Поддерживается ли Python 2 и стоит ли его использоватьPython 1 — с чего начиналась история языкаКоманда python print - полное руководство по выводу данныхПравила именования переменных в PythonПользовательские исключения в PythonОсновы Python coreОписание объектов PythonНаследование классов в Python — основы и примерыМножественное наследование в Python — примеры и MROКонтекстный менеджер with в Python — как работает и зачем нуженКомментарии в Python — однострочные, многострочные и docstringКакой Python выбрать для установкиКак вывести целое число с помощью print в PythonКак установить Python на Windows macOS и LinuxКак пользоваться консолью PythonКак получить последний элемент в PythonКак найти значение в PythonКак настроить PythonКак использовать print для строк в PythonКак работает интерпретатор PythonИнструкция по работе с PythonБлок finally в обработке исключений PythonЦелые числа в PythonАбстрактные классы в Python — ABC и abstractmethod
Pydantic: валидация данных в Python
Загрузка данных PythonУправление проектами на GitHub с PythonСоздание веб-приложений на Flask PythonСоздание бота на PythonСоздание интерфейсов Python QTСоздание игр с PygameСоздание GUI в PythonКак работать со словарями в PythonРабота с библиотеками через Python PackagingРабота со временем в Python при помощи модуля timePython name — особенности переменнойМатематические операции в Python с модулем mathPython listing — что это и как использоватьPytest — тестирование на Python: полное руководствоОбработка изображений с OpenCV PythonNumPy в Python — основы и применение в задачахМашинное обучение с PythonИспользование Anaconda с PythonМодуль contextlib в Python — утилиты для контекстных менеджеровБиблиотеки Python и их применение в проектах
Возврат значений из функции в PythonВложенные функции в PythonСоздание собственных декораторов в PythonРабота с функцией map в PythonЦикл while в Python и примеры использованияОбработка чисел, введённых через input в PythonОсновные операторы в Python с примерамиУсловные выражения if else в Python для начинающихКак выполняется вызов функций call в PythonПродвинутые генераторы в Python — send, throw, close и корутиныПозиционные и именованные аргументы в PythonОбъявление переменных и управление областью видимости в PythonПередача аргументов по ссылке и по значению в PythonПередача аргументов через args и kwargs в PythonОсновные методы Python и примеры их использованияОператор match/case в Python 3.10+ — основы структурного сопоставленияПаттерны match/case в Python — деструктуризация, guard и вложенные шаблоныПрактические примеры match/case в Python — реальные сценарии примененияЛокальные и глобальные переменные в PythonЧасто используемые команды PythonКлючевые слова global и nonlocal в PythonКак создавать функции в PythonКак работает сборщик мусора в PythonКак работает область видимости переменных в PythonКак работает функция callable в PythonКак работает функция any и all в PythonКак проверить тип переменной в PythonКак передать функцию как аргумент в PythonКак использовать функцию isinstance в PythonКак использовать функцию filter в PythonКак использовать функцию eval безопасно в PythonКак использовать функцию filter в PythonКак использовать декораторы в PythonИзменяемые и неизменяемые типы данных в PythonГенераторы и yield в Python — как создавать и использоватьГенераторные выражения в Python — синтаксис и примерыФункции в Python и способы их вызоваФункции как объекты в PythonЧто такое замыкания в PythonЧто делает функция reduce в PythonЧто делает функция id в PythonАргументы по умолчанию в PythonАнонимные функции и lambda в PythonАлгоритмы на Python — примеры и объяснение
Запись данных в PythonУстановка pip в PythonУправление библиотеками с помощью Python PackagingУправление зависимостями requirement в PythonУдаление пробелов с помощью strip в PythonСтруктурирование кода в PythonСоздание исполняемого файла Python в exeРазбор traceback в модуле PythonРазбор site-packages в PythonРазбор Program Files в PythonРабота с Unicode кодировками в PythonРабота с системными функциями Python sysРабота с папкой AppData в PythonРабота с модулем logging в PythonРабота с каталогами в PythonРабота с CSV в PythonВиртуальная среда venv в Python — создание и настройкаКак создать простое приложение на PythonИспользование pip в Python для установки пакетовМодули в Python и организация кода в проектеИмпорт модулей в Python и правила подключенияРабота с файлами в Python пошаговоЧто делает компилятор Python и как он работаетПолучение строки из модуля PythonПодключение файлов в Python с includeПеременные среды в PythonСборка проекта с помощью packaging в PythonНастройка Python сервераИспользование Python на UbuntuИспользование консоли PythonИспользование кодировок в PythonИнициализация пакетов PythonИмпорт модулей PythonИмпорт имен в PythonСреда IDLE Python и базовые возможностиЧтение и запись TXT в PythonЧтение файлов в Python с помощью open file
Удаление элементов из списка PythonТипы данных в Python — обзор и рекомендацииМетоды str в Python и обработка текстаОсновные операции со строками в PythonСписки в Python и их ключевые методыСоздание списков данных в PythonРабота со строками и символами в PythonРабота со столбцами в PythonРабота со списком значений в PythonРабота с таблицами в Python с помощью DataFrameРабота с RFR в PythonРабота с пробелами в PythonРабота с массивами в PythonРабота с кортежами tuple PythonРабота с координатами X и Y в PythonРабота с ключами в PythonРабота с элементами данных PythonРабота с двоичными числами PythonРабота с данными в PythonРабота с данными NumPy PythonРабота с большими числами в PythonРабота с битами в PythonРабота с байтами в PythonЧто такое значение в Python и как его определитьМножества в Python и операции с нимиИспользование range в Python для цикловПроверка на четность в PythonПроверка числа в PythonПреобразование списка в строку PythonПреобразование типов в PythonПреобразование числа в строку в PythonПостроение графиков в PythonОпределение индекса элемента в PythonОкругление чисел в PythonОбъединение списков в Python с помощью zipМножества в PythonМассивы в Python и отличие от списковМассив чисел в PythonКортежи данных в PythonКак вычислить сумму чисел в PythonКак получить остаток от деления в PythonКак найти следующее число в PythonИспользование Unicode в PythonТип int в Python и его особенностиИндекс списка в PythonФункции для работы со строками в PythonЭлементы Python и способы доступа к нимДоступ к элементам массива в PythonДеление чисел в PythonРабота с данными в Python на практикеКак работать с числами в Python
Открыть базу знаний

Лучшие курсы по теме

Иконка молнииНовый
изображение курса

Основы Python

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий