Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Enum — перечисления для типобезопасности
Enum (Enumeration) — это класс Python, который позволяет определить набор именованных констант. Это мощный инструмент для создания типобезопасного кода и улучшения его читаемости.
Основная проблема без Enum
Плохой подход — строковые константы
# Это работает, но опасно
user_status = "active"
if user_status == "active":
print("Пользователь активен")
elif user_status == "inactive":
print("Пользователь неактивен")
elif user_status == "banned": # Опечатка!
print("Пользователь заблокирован")
# Проблемы:
# 1. Легко опечататься: "acctive" вместо "active"
# 2. IDE не может подсказать возможные значения
# 3. Нельзя сделать type checking
# 4. Можно передать любую строку
Хороший подход — Enum
from enum import Enum
class UserStatus(Enum):
ACTIVE = "active"
INACTIVE = "inactive"
BANNED = "banned"
# Теперь это типобезопасно
user_status = UserStatus.ACTIVE
if user_status == UserStatus.ACTIVE:
print("Пользователь активен")
elif user_status == UserStatus.INACTIVE:
print("Пользователь неактивен")
# Ошибку будет видна сразу
# user_status = UserStatus.ACTTIVE # AttributeError!
Основные преимущества Enum
1. Типобезопасность
from enum import Enum
from typing import Literal
class OrderStatus(Enum):
PENDING = "pending"
PROCESSING = "processing"
SHIPPED = "shipped"
DELIVERED = "delivered"
class Order:
def __init__(self, status: OrderStatus): # Type hint!
if not isinstance(status, OrderStatus):
raise TypeError(f"Expected OrderStatus, got {type(status)}")
self.status = status
# IDE подскажет возможные значения
order = Order(OrderStatus.PENDING) # ✓ Правильно
order = Order("pending") # ✗ IDE предупредит
2. Читаемость кода
# Без Enum
if payment_method == "CC":
charge_credit_card()
elif payment_method == "BTC":
charge_bitcoin()
elif payment_method == "PP":
charge_paypal()
# С Enum
class PaymentMethod(Enum):
CREDIT_CARD = "CC"
BITCOIN = "BTC"
PAYPAL = "PP"
if payment_method == PaymentMethod.CREDIT_CARD:
charge_credit_card()
elif payment_method == PaymentMethod.BITCOIN:
charge_bitcoin()
elif payment_method == PaymentMethod.PAYPAL:
charge_paypal()
# Второй вариант очевидно более читаем!
3. Автодополнение в IDE
class Role(Enum):
ADMIN = "admin"
USER = "user"
MODERATOR = "moderator"
# IDE покажет все доступные значения
role = Role. # Появится список: ADMIN, USER, MODERATOR
4. Валидация на уровне типов
from typing import Protocol
class UserStatus(Enum):
ACTIVE = "active"
INACTIVE = "inactive"
BANNED = "banned"
def update_user_status(user_id: int, status: UserStatus) -> None:
"""Только Enum значения приемлются"""
# mypy проверит типы
pass
update_user_status(1, UserStatus.ACTIVE) # ✓ OK
update_user_status(1, "active") # ✗ mypy ошибка
Практические примеры
Пример 1: Статусы в БД
from enum import Enum
from sqlalchemy import Column, String, Enum as SQLEnum
class OrderStatus(Enum):
NEW = "new"
CONFIRMED = "confirmed"
SHIPPED = "shipped"
DELIVERED = "delivered"
CANCELLED = "cancelled"
class Order(Base):
__tablename__ = "orders"
id = Column(Integer, primary_key=True)
status = Column(
SQLEnum(OrderStatus), # SQLAlchemy знает про Enum
default=OrderStatus.NEW,
nullable=False
)
# Использование
order = Order(status=OrderStatus.NEW)
if order.status == OrderStatus.SHIPPED:
send_notification()
Пример 2: Роли и permissions
from enum import Enum, auto
class Permission(Enum):
CREATE = auto()
READ = auto()
UPDATE = auto()
DELETE = auto()
class Role(Enum):
ADMIN = {
Permission.CREATE,
Permission.READ,
Permission.UPDATE,
Permission.DELETE
}
EDITOR = {
Permission.CREATE,
Permission.READ,
Permission.UPDATE
}
VIEWER = {
Permission.READ
}
class User:
def __init__(self, role: Role):
self.role = role
def can(self, permission: Permission) -> bool:
return permission in self.role.value
# Использование
admin = User(Role.ADMIN)
print(admin.can(Permission.DELETE)) # True
viewer = User(Role.VIEWER)
print(viewer.can(Permission.DELETE)) # False
Пример 3: API для Pydantic
from enum import Enum
from pydantic import BaseModel, field_validator
class ProductCategory(Enum):
ELECTRONICS = "electronics"
CLOTHING = "clothing"
FOOD = "food"
HOME = "home"
class Product(BaseModel):
name: str
category: ProductCategory # Type safe!
price: float
@field_validator('price')
@classmethod
def price_must_be_positive(cls, v):
if v <= 0:
raise ValueError('Price must be positive')
return v
# Использование
product_data = {
"name": "Laptop",
"category": "electronics", # Строка автоматически преобразуется
"price": 999.99
}
product = Product(**product_data)
print(product.category) # ProductCategory.ELECTRONICS
print(product.category.value) # "electronics"
Пример 4: Сравнение и итерация
from enum import Enum
class Environment(Enum):
DEVELOPMENT = "dev"
STAGING = "staging"
PRODUCTION = "prod"
# Сравнение
env = Environment.DEVELOPMENT
if env == Environment.DEVELOPMENT:
print("Режим разработки")
# Получение значения
print(env.name) # "DEVELOPMENT"
print(env.value) # "dev"
# Итерация по всем значениям
for env in Environment:
print(f"{env.name}: {env.value}")
# Преобразование из строки
env_str = "prod"
env = Environment(env_str) # Найдет PRODUCTION
# Преобразование по имени
env = Environment["DEVELOPMENT"] # Найдет DEVELOPMENT
Пример 5: IntEnum для числовых значений
from enum import IntEnum
class HttpStatus(IntEnum):
OK = 200
CREATED = 201
BAD_REQUEST = 400
UNAUTHORIZED = 401
NOT_FOUND = 404
SERVER_ERROR = 500
# IntEnum позволяет сравнивать с числами
if HttpStatus.OK == 200: # True!
print("OK")
if HttpStatus.OK > 100: # True! Сравнение как с числом
print("Success code")
status_code = HttpStatus.NOT_FOUND
print(status_code + 1) # 405 (можно арифметика)
Пример 6: Flag для битовых флагов
from enum import Flag, auto
class Permission(Flag):
READ = auto() # 1
WRITE = auto() # 2
EXECUTE = auto() # 4
DELETE = auto() # 8
# Комбинирование флагов
user_permissions = Permission.READ | Permission.WRITE
# Проверка флагов
if Permission.READ in user_permissions:
print("Может читать")
if Permission.DELETE in user_permissions:
print("Может удалять")
else:
print("Не может удалять")
Когда использовать Enum
✓ Используй Enum когда:
- Есть фиксированный набор значений
- Значения не меняются во время выполнения
- Нужна типобезопасность
- Хочешь улучшить читаемость
- Используешь mypy для проверки типов
- Работаешь со статусами, ролями, категориями
✗ НЕ используй Enum когда:
- Значения динамические (загружаются из БД)
- Много возможных значений
- Значения часто меняются
Итог
Enum — это мощный инструмент для:
- Типобезопасности — IDE и mypy проверяют
- Читаемости — явные имена вместо волшебных строк
- Автодополнения — IDE подсказывает варианты
- Валидации — нельзя передать неправильное значение
- Поддержки — будущие разработчики поймут код сразу
Это best practice в современной разработке на Python.