1. Вступление: Проблема «магических строк»

Бывало такое: ты пишешь код, всё кажется логичным, но программа работает не так, как должна? Ты сидишь час, перебираешь функции и вдруг замечаешь, что в одном месте написал статус заказа как "shipped", а в другом — случайно опечатался и написал "shiped" (с одной «p»).

Поздравляю, ты попался в ловушку «магических строк».

Магические строки — это когда ты используешь обычный текст для управления логикой программы. Например, проверяешь статус через if status == "pending".

Почему это превращается в кошмар для новичка (и не только):

  1. Python молчит об ошибках. Если ты ошибешься в названии функции, Python выдаст ошибку. Но если ты опечатаешься в строке "pending", компьютер этого не заметит. Для него это просто другой текст. В итоге заказ «зависает», а ты не понимаешь почему.

  2. Память не вечна. Через неделю ты забудешь, как именно называл статус: "in_progress", "processing" или "active". Придется каждый раз листать код назад и искать, что же ты там написал.

  3. Угадайка вместо подсказок. Твой редактор кода (IDE) обожает помогать тебе, когда ты ставишь точку после названия переменной. Но со строками он бессилен — он не знает, какие именно слова ты задумал использовать.

В итоге твой код превращается в хрупкую конструкцию, которая держится на твоей внимательности. А внимательность — ресурс ограниченный. Чтобы не превращать разработку в игру «найди 10 отличий в словах», умные люди придумали Enum.

2. Решение: Модуль enum

Чтобы навести порядок в этом хаосе со строками, в Python есть встроенный инструмент — модуль enum (сокращение от enumeration — перечисление).

Что это такое?
Представь, что ты создаешь «закрытый клуб» для своих статусов. В этот клуб нельзя просто так зайти с улицы с любой строкой — там действуют только те имена, которые ты официально утвердил.

Как это выглядит в коде:

Вместо того чтобы надеяться на память, мы создаем специальный класс:

from enum import Enum

class OrderStatus(Enum):
    PENDING = "pending"
    SHIPPED = "shipped"
    DELIVERED = "delivered"

В чем здесь магия?

  1. Теперь это не просто текст, а объект. Когда ты пишешь OrderStatus.PENDING, Python точно знает, что это за сущность.

  2. Автодополнение. Как только ты напишешь OrderStatus. и поставишь точку, твой редактор сам предложит список: PENDING, SHIPPED, DELIVERED. Опечататься теперь физически невозможно — ты просто выбираешь вариант из списка.

  3. Читаемость. Посмотри на это сравнение:

    • Было: if status == "shipped": (Просто текст, за которым может стоять что угодно).

    • Стало: if status == OrderStatus.SHIPPED: (Явно видно: мы сравниваем статус заказа с конкретным состоянием «Доставлено»).

Главная фишка:
Если ты вдруг решишь изменить строку "shipped" на "in_transit", тебе не придется искать её по всему проекту. Ты изменишь её только в одном месте — внутри класса OrderStatus, и всё остальное продолжит работать автоматически.

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

3. Преимущества использования Enum

Если коротко: это делает твою жизнь как программиста намного спокойнее. Вот четыре главные причины:

1. Подсказки от IDE (Твой «умный» помощник)
Когда ты используешь строки, ты один на один со своей памятью. Но как только ты вводишь Enum, твой редактор кода (PyCharm, VS Code и др.) начинает тебе помогать.

  • Как это работает: Ты ставишь точку после имени класса — и вуаля! Весь список доступных статусов перед глазами. Тебе не нужно помнить, как пишется «отправлено» — ты просто выбираешь это из списка.

2. Единственный источник истины (Single Source of Truth)
Представь, что у тебя проект на 20 файлов. В 10 из них ты проверяешь статус "pending". И тут заказчик говорит: «Давайте заменим "pending" на "awaiting_payment"».

  • Со строками: Тебе нужно пройтись поиском по всему проекту и аккуратно заменить текст, боясь зацепить лишнее.

  • С Enum: Ты меняешь значение в одной строчке внутри класса. Всё. Во всем остальном коде изменения подхватятся автоматически.

3. Код, который объясняет сам себя
Enum делает код «самодокументированным». Когда другой человек (или ты сам через месяц) откроет твой файл, он сразу увидит:

class OrderStatus(Enum):
    PENDING = 1
    SHIPPED = 2
    DELIVERED = 3

Ему не нужно искать по всей программе, какие вообще бывают статусы. Он просто смотрит на этот класс и сразу понимает всю бизнес-логику процесса.

4. Защита от «случайных пассажиров»
Строка — это слишком свободный формат. В переменную status можно записать "shipped", а можно — "я-у-мамы-программист". Python это проглотит.
С Enum ты можешь строго ограничить выбор. Если функция ожидает OrderStatus, ты уже не сможешь передать туда случайный текст. Это создает своего рода «защитный барьер», который отсекает глупые ошибки еще на этапе написания кода.

4. Продвинутый уровень: IntEnum

Обычный Enum — штука классная, но строгая. Если ты создашь OrderStatus.PENDING = 1, а потом попробуешь сравнить его просто с числом (if status == 1), Python скажет: «Э, нет, это разные вещи!». Для него объект перечисления не равен числу, даже если внутри него спрятана единица.

Но в реальности мы часто получаем данные из баз данных или через API в виде обычных чисел. И тут на сцену выходит IntEnum.

Что это такое?
Это «прокачанный» вариант перечисления, который ведет себя и как ваш класс, и как обычное целое число одновременно.

Как это выглядит:

from enum import IntEnum

class OrderStatus(IntEnum):
    PENDING = 1
    SHIPPED = 2
    DELIVERED = 3

# Теперь магия:
status = 1

if status == OrderStatus.PENDING:
    print("Всё сработает!")  # Это условие выполнится

Зачем это нужно?

  1. Дружба с базами данных: В БД статусы часто хранятся как 1, 2, 3. С IntEnum тебе не нужно превращать каждое число из базы в объект — сравнение сработает само собой.

  2. Меньше лишнего кода: Тебе не придется каждый раз дописывать .value (например, status.value == 1), чтобы просто сравнить значения.

  3. Математика и сортировка: Если твои статусы имеют «вес» (например, приоритет задачи: LOW = 1, HIGH = 5), то IntEnum позволит их сравнивать: if priority > Priority.LOW.

Короткий совет:
Если твои статусы — это просто названия (как «красный», «синий»), используй обычный Enum. Но если за ними стоят реальные числа, которые приходят извне или которые нужно сравнивать «больше-меньше» — бери IntEnum. Это сэкономит тебе кучу нервов при отладке.

6. Итог: «До и После»

❌ КАК БЫЛО: Код на «магических строках»

def check_order_status(status):
    if status == "pending":
        return "⏳ Ждем оплаты..."
    elif status == "shiped":  # ОЙ! Опечатка (одна 'p'), которую никто не заметит
        return "? Заказ в пути!"
    elif status == "delivered":
        return "✅ Доставлено!"

# Работает? Вроде да. Безопасно? Ни разу.
print(check_order_status("shipped")) # Вернет None, потому что в функции опечатка

Минусы:

  • Опечатка-невидимка: Ты написал "shiped", Python промолчал, клиент не получил уведомление.

  • Угадайка: Если ты забудешь, как называется статус, придется искать его по всему проекту.

  • Хрупкость: Решил изменить "pending" на "waiting"? Удачи найти и заменить это во всех 50 файлах проекта.


✅ КАК СТАЛО: Код с использованием IntEnum

from enum import IntEnum

class OrderStatus(IntEnum):
    PENDING = 1
    SHIPPED = 2
    DELIVERED = 3

def check_order_status(status: OrderStatus):
    if status == OrderStatus.PENDING:
        return "⏳ Ждем оплаты..."
    elif status == OrderStatus.SHIPPED:
        return "? Заказ в пути!"
    elif status == OrderStatus.DELIVERED:
        return "✅ Доставлено!"

# Теперь IDE сама подскажет: OrderStatus.SHIPPED
print(check_order_status(OrderStatus.SHIPPED))

Плюсы:

  • Никаких опечаток: Если ты попробуешь написать OrderStatus.SHIPED, Python тут же выдаст ошибку AttributeError. Ты поймаешь баг еще до того, как запустишь код.

  • Помощь друга: Твой редактор кода сам предложит список статусов — просто нажми точку.

  • Порядок: Все состояния системы описаны в одном небольшом классе. Это и есть профессиональный подход.

Вывод: Использование Enum — это не «усложнение», это страховка. Ты тратишь 30 секунд на создание класса, чтобы потом не тратить 2 часа на поиск дурацкой опечатки.

7. Практическое задание (ДЗ)

Пора засучить рукава и превратить «хрупкий» код в надежный. Ниже — типичный фрагмент программы для управления логистикой, который написан на строках.

Твоя задача:

  1. Импортируй IntEnum из модуля enum.

  2. Создай класс OrderStatus(IntEnum), в котором будут три статуса: PENDING, SHIPPED и DELIVERED. Присвой им любые числа (например, 1, 2, 3).

  3. Перепиши функцию и вызовы так, чтобы вместо текстовых строк использовались участники твоего нового класса.

Исходный («плохой») код:

def get_delivery_message(status):
    if status == "pending":
        return "? Заказ обрабатывается, скоро отправим!"
    elif status == "shipped":
        return "? Заказ уже в пути, ожидайте."
    elif status == "delivered":
        return "? Заказ доставлен! Наслаждайтесь покупкой."
    else:
        return "❓ Неизвестный статус заказа."

# Тестируем:
print(get_delivery_message("shipped"))
print(get_delivery_message("shiped")) # Ошибка, которую мы не заметим без Enum

Анонсы новых статей, полезные материалы, а так же если в процессе у вас возникнут сложности, обсудить их или задать вопрос по этой статье можно в моём Telegram-сообществе. Смело заходите, если что-то пойдет не так, — постараемся разобраться вместе.

? Подсказка для проверки:
Когда закончишь, попробуй передать в функцию число вместо объекта (например, 2). Поскольку ты используешь IntEnum, код должен сработать правильно. Это и есть та самая гибкость, о которой мы говорили!

Комментарии (23)


  1. Draas
    08.01.2026 08:33

    Очень сильно пахнет ГПТшкой (оформление триггернуло), два - а разве мысль о том, что хранить состояния в строках и использовать фиксированные значения больше, чем в одном месте - это скорее плохо, не очевидная? Впрочем, сам не питонист. Если нужны именно строки для состояний - проще тогда завести класс с константами и там их хранить, и никаких проблем.


    1. enamored_poc Автор
      08.01.2026 08:33

      По поводу оформления — справедливо, привычка структурировать всё по полочкам иногда делает текст похожим на мануал :)

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

      Почему не просто класс с константами? Можно и так, но Enum в Python — это не просто группировка. Это защита от дублирования значений, возможность типизации и удобная работа с именами/значениями (name/value) без костылей. Для простых скриптов константы ок, для чего-то сложнее — Enum безопаснее


    1. ValeryIvanov
      08.01.2026 08:33

      С константами есть проблема - IDE/typechecker не станет ругаться, если не покрыть все значения. С перечислениями(Enum/Literal/Union - неважно), ситуация принципиально иная. Например:

      Константы без else ветки
      FAIL = 1
      SUCCESS = 2
      PROCESSING = 3
      
      def process(status: int) -> str: # typechecker ругается, что не во всех случаях возвращается строка
          if status == FAIL:
              return 'fail'
          elif status == SUCCESS:
              return 'success'
          elif status == PROCESSING:
              return 'processing'
      

      В этом случае тайпчекер будет ругаться, так как не все возможные значения для status покрыты. Придётся добавить ветку else. Мало того, что нужно будет как-то обработать невозможное значение для status, так ещё и в случае появления новой константы для статуса, мы никак не узнаем, что не обработали её.

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

      Перечисления без else ветки
      class Status(enum.Enum):
          FAIL = enum.auto()
          SUCCESS = enum.auto()
          PROCESSING = enum.auto()
      
      def process_status(status: Status) -> str: # всё в порядке, typechecker знает, что мы обработали все возможные значения
          if status is Status.FAIL:
              return 'fail'
          elif status is Status.SUCCESS:
              return 'success'
          elif status is Status.PROCESSING:
              return 'processing'
      


    1. Tishka17
      08.01.2026 08:33

      Автор каждые несколько дней выдает очередной опус, маловероятно что он сам это пишет


  1. Vindicar
    08.01.2026 08:33

    Лишние метафоры, спискота, эмодзи в заголовках... 100% генеративщина ради ссылки на телеграм.


    1. myhicursed
      08.01.2026 08:33

      так и есть, статья ради статьи. уникальности 0. на хабре уже есть хорошая статья по enum, и она более подробнее описывает.

      а не кучу воды вокруг "вы можете теперь не передавать сухие строки и мэджик числа в условия, радуйтесь"


  1. Farongy
    08.01.2026 08:33

    Можно перейти к классам с общим интерфейсом.

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


    1. myhicursed
      08.01.2026 08:33

      автор не знает что это, ему как гпт написал он так и сделает


    1. jlllk
      08.01.2026 08:33

      Новый класс ради одной строчки? Я вас поавильно понял?


      1. olivera507224
        08.01.2026 08:33

        Ну не новый модуль же, класса будет достаточно.


  1. ialexander
    08.01.2026 08:33

    О повеяло Бобом Мартином и его магическими числами, правда гораздо более многословно.

    Но вы правы, использовать строчные литералы в коде - плохая идея, но это больше ошибка новичков, общая рекомендация в том же Python, использовать Enum. К примеру в документации FastAPI https://fastapi.tiangolo.com/tutorial/path-params/#predefined-values


    1. nerudo
      08.01.2026 08:33

      Использовать магические константы в коде плохо, это все знают. Поэтому настоящие программисты пишут так:
      #define MAGIC_ZERO 0
      #define MAGIC_ONE 1
      и так до 30, что ли. Реальный код непомню где, у analog devices возможно


  1. ganqqwerty
    08.01.2026 08:33

    товарищ, не ленись писать статьи ручками!


    1. enamored_poc Автор
      08.01.2026 08:33

      А что вам не понравилось в статье? Или может вы с чем то не согласны в статье? Не ленитесь как то аргументировать вашу позицию)


      1. jlllk
        08.01.2026 08:33

        Вы первый раз на Хабре? Когда-то тут было много контента, в который авторы вкладывали души, который представлял ценность. Еще остались воспоминания о тех славных временах. По этой причине тут не ценится нейрогенерация. Особенно по избитым темам.


      1. Lord_of_Rings
        08.01.2026 08:33

        А что вам не понравилось в статье

        То, что статья - плод творения ллм


        1. enamored_poc Автор
          08.01.2026 08:33

          аргумент)


          1. ganqqwerty
            08.01.2026 08:33

            собственно на этом всё


            1. enamored_poc Автор
              08.01.2026 08:33

              понял


      1. DSSilver
        08.01.2026 08:33

        Статья не понравилась тем, что Вы здесь, как автор, лишний. У вас здесь просто сырая выдача LLM, которую каждый может получить за минуту. Статья не несет следа Вашей компетенции. Но в эту статью вы не забыли добавить ссылку на свой телеграм-канал. При том, что непонятно, чем он может быть ценен. Другими копипастами из LLM? Потому что, повторюсь, статья, при ее технической корректности, Вашу экспертность скорее антиутверждает


  1. Tishka17
    08.01.2026 08:33

    Обычный Enum — штука классная, но строгая. Если ты создашь OrderStatus.PENDING = 1, а потом попробуешь сравнить его просто с числом (if status == 1), Python скажет: «Э, нет, это разные вещи!». Для него объект перечисления не равен числу, даже если внутри него спрятана единица.

    Но в реальности мы часто получаем данные из баз данных или через API в виде обычных чисел. И тут на сцену выходит IntEnum.

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


  1. Markgresilov
    08.01.2026 08:33

    Жалко, что в питоне нету встроенной поддержки enum на уровне синтаксиса, как в C++, к примеру. А то так выходит много абстракций и всё-таки это чуть более громоздко.


  1. YuriyPashkov
    08.01.2026 08:33

    Код на «магических строках»

    Погодите, так реально что ли пишут на питоне? И там что, нет поддержки enum из коробки, что вот это всё надо городить? Или это какой-то галюциногенный угар от чатжпт?