Python StrEnum: строковое значение без .value
StrEnum появился в Python 3.11 и делает членов перечисления строками: str(member) возвращает значение, а не имя вида Status.NEW. Такое перечисление удобно передавать в JSON, SQL-параметры и API без ручного .value. Оно также сравнивается с обычной строкой и работает как ключ словаря.
Объявить строковое перечисление
from enum import StrEnum
import json
class Status(StrEnum):
NEW = "new"
DONE = "done"
status = Status.NEW
print(status) # new
print(status == "new") # True
print(json.dumps({"status": status})) # {"status": "new"}json.dumps() сериализует член как строку, потому что StrEnum наследуется от str. Обычный Enum в такой ситуации вызвал бы TypeError. При чтении из внешнего источника создавайте член явно: Status("new"); неизвестное значение вызовет ValueError, и это лучше, чем молча принять опечатку.
Если нужен автогенерируемый код, используйте auto(): в StrEnum он берёт имя члена в нижнем регистре. Явные значения всё равно предпочтительнее для стабильного контракта API: переименование поля не должно менять данные, которые уже сохранены в базе.
Сравнить с обычным Enum
from enum import Enum
class LegacyStatus(str, Enum):
NEW = "new"
print(str(LegacyStatus.NEW)) # LegacyStatus.NEW
print(LegacyStatus.NEW == "new") # TrueКласс str, Enum тоже сравнивается со строкой, но str() возвращает LegacyStatus.NEW, что ломает f-строки и логи. StrEnum решает именно эту проблему. При этом repr() остаётся <Status.NEW: 'new'>, что удобно для отладки.
Не используйте StrEnum там, где важна строгая типизация: равенство с произвольной строкой может скрыть ошибку. Если значение приходит из ненадёжного источника, валидируйте его через конструктор перечисления и возвращайте 400/422, а не пропускайте дальше. Для числовых кодов есть IntEnum, но смешивать его с произвольными числами так же опасно.
Документация: enum.StrEnum, Enum HOWTO.