1. Вступление: Проблема «магических строк»
Бывало такое: ты пишешь код, всё кажется логичным, но программа работает не так, как должна? Ты сидишь час, перебираешь функции и вдруг замечаешь, что в одном месте написал статус заказа как "shipped", а в другом — случайно опечатался и написал "shiped" (с одной «p»).
Поздравляю, ты попался в ловушку «магических строк».
Магические строки — это когда ты используешь обычный текст для управления логикой программы. Например, проверяешь статус через if status == "pending".
Почему это превращается в кошмар для новичка (и не только):
Python молчит об ошибках. Если ты ошибешься в названии функции, Python выдаст ошибку. Но если ты опечатаешься в строке
"pending", компьютер этого не заметит. Для него это просто другой текст. В итоге заказ «зависает», а ты не понимаешь почему.Память не вечна. Через неделю ты забудешь, как именно называл статус:
"in_progress","processing"или"active". Придется каждый раз листать код назад и искать, что же ты там написал.Угадайка вместо подсказок. Твой редактор кода (IDE) обожает помогать тебе, когда ты ставишь точку после названия переменной. Но со строками он бессилен — он не знает, какие именно слова ты задумал использовать.
В итоге твой код превращается в хрупкую конструкцию, которая держится на твоей внимательности. А внимательность — ресурс ограниченный. Чтобы не превращать разработку в игру «найди 10 отличий в словах», умные люди придумали Enum.
2. Решение: Модуль enum
Чтобы навести порядок в этом хаосе со строками, в Python есть встроенный инструмент — модуль enum (сокращение от enumeration — перечисление).
Что это такое?
Представь, что ты создаешь «закрытый клуб» для своих статусов. В этот клуб нельзя просто так зайти с улицы с любой строкой — там действуют только те имена, которые ты официально утвердил.
Как это выглядит в коде:
Вместо того чтобы надеяться на память, мы создаем специальный класс:
from enum import Enum
class OrderStatus(Enum):
PENDING = "pending"
SHIPPED = "shipped"
DELIVERED = "delivered"
В чем здесь магия?
Теперь это не просто текст, а объект. Когда ты пишешь
OrderStatus.PENDING, Python точно знает, что это за сущность.Автодополнение. Как только ты напишешь
OrderStatus.и поставишь точку, твой редактор сам предложит список:PENDING,SHIPPED,DELIVERED. Опечататься теперь физически невозможно — ты просто выбираешь вариант из списка.-
Читаемость. Посмотри на это сравнение:
Было:
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, 2, 3. СIntEnumтебе не нужно превращать каждое число из базы в объект — сравнение сработает само собой.Меньше лишнего кода: Тебе не придется каждый раз дописывать
.value(например,status.value == 1), чтобы просто сравнить значения.Математика и сортировка: Если твои статусы имеют «вес» (например, приоритет задачи:
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. Практическое задание (ДЗ)
Пора засучить рукава и превратить «хрупкий» код в надежный. Ниже — типичный фрагмент программы для управления логистикой, который написан на строках.
Твоя задача:
Импортируй
IntEnumиз модуляenum.Создай класс
OrderStatus(IntEnum), в котором будут три статуса:PENDING,SHIPPEDиDELIVERED. Присвой им любые числа (например, 1, 2, 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)

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

myhicursed
08.01.2026 08:33так и есть, статья ради статьи. уникальности 0. на хабре уже есть хорошая статья по enum, и она более подробнее описывает.
а не кучу воды вокруг "вы можете теперь не передавать сухие строки и мэджик числа в условия, радуйтесь"

Farongy
08.01.2026 08:33Можно перейти к классам с общим интерфейсом.
Тогда будет позднее связывание, и в случае добавления статуса нужно будет добавить новый класс, а не делать изменение в двух местах. В случае изменения это изменение тоже будет в одном месте.

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

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

ganqqwerty
08.01.2026 08:33товарищ, не ленись писать статьи ручками!

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

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

Lord_of_Rings
08.01.2026 08:33А что вам не понравилось в статье
То, что статья - плод творения ллм

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

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

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

YuriyPashkov
08.01.2026 08:33Код на «магических строках»
Погодите, так реально что ли пишут на питоне? И там что, нет поддержки enum из коробки, что вот это всё надо городить? Или это какой-то галюциногенный угар от чатжпт?
Draas
Очень сильно пахнет ГПТшкой (оформление триггернуло), два - а разве мысль о том, что хранить состояния в строках и использовать фиксированные значения больше, чем в одном месте - это скорее плохо, не очевидная? Впрочем, сам не питонист. Если нужны именно строки для состояний - проще тогда завести класс с константами и там их хранить, и никаких проблем.
enamored_poc Автор
По поводу оформления — справедливо, привычка структурировать всё по полочкам иногда делает текст похожим на мануал :)
Насчет "очевидности" — вы правы, это база. Но, как показывает аудит чужого кода, "база" — это то, на чем чаще всего сыплются.
Почему не просто класс с константами? Можно и так, но Enum в Python — это не просто группировка. Это защита от дублирования значений, возможность типизации и удобная работа с именами/значениями (name/value) без костылей. Для простых скриптов константы ок, для чего-то сложнее — Enum безопаснее
ValeryIvanov
С константами есть проблема - IDE/typechecker не станет ругаться, если не покрыть все значения. С перечислениями(Enum/Literal/Union - неважно), ситуация принципиально иная. Например:
Константы без else ветки
В этом случае тайпчекер будет ругаться, так как не все возможные значения для status покрыты. Придётся добавить ветку else. Мало того, что нужно будет как-то обработать невозможное значение для status, так ещё и в случае появления новой константы для статуса, мы никак не узнаем, что не обработали её.
В случае же с перечислениями, мы не обязаны иметь ветку else и ещё до запуска узнаем о том, что не обработали одно из возможных значений для статуса. Пример:
Перечисления без else ветки
Tishka17
Автор каждые несколько дней выдает очередной опус, маловероятно что он сам это пишет