← Назад к вопросам

Что такое конечный автомат?

2.0 Middle🔥 111 комментариев
#Python Core#Soft Skills

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

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Конечный автомат (Finite State Machine, FSM)

Конечный автомат — это математическая модель вычислений, которая определяет систему с конечным числом состояний. Система переходит между состояниями на основе входных событий. Это мощный инструмент для моделирования поведения в реальном времени.

Основные компоненты

Конечный автомат состоит из:

1. СОСТОЯНИЯ (States)
   - Конечное множество возможных состояний
   - Система может находиться только в ОДНОМ состоянии
   - Пример: idle, running, paused, stopped

2. СОБЫТИЯ (Events/Inputs)
   - Триггеры которые вызывают переходы
   - Пример: click, timer, error, user_input

3. ПЕРЕХОДЫ (Transitions)
   - Правила перехода из одного состояния в другое
   - На основе текущего состояния и события
   - Пример: idle + click → running

4. НАЧАЛЬНОЕ СОСТОЯНИЕ (Initial State)
   - Состояние когда система стартует
   - Пример: idle

5. ФИНАЛЬНЫЕ СОСТОЯНИЯ (Final/Accepting States)
   - Состояния когда процесс завершён
   - Опционально
   - Пример: stopped

Классический пример: Светофор

Светофор как FSM:

          ↓ timer=30s
    ┌────────────┐
    │   RED      │
    └────────┬───┘
             │
             ↓ timer=25s
    ┌────────────┐
    │   GREEN    │
    └────────┬───┘
             │
             ↓ timer=5s
    ┌────────────┐
    │   YELLOW   │
    └────────┬───┘
             │
             └─────────────┘

Состояния: RED, GREEN, YELLOW
События: timer=30s, timer=25s, timer=5s
Переходы: RED→GREEN, GREEN→YELLOW, YELLOW→RED

Практический пример на Python

from enum import Enum
from dataclasses import dataclass
from typing import Callable, Dict, Optional

class State(Enum):
    """Возможные состояния."""
    IDLE = "idle"
    LOADING = "loading"
    SUCCESS = "success"
    ERROR = "error"

class Event(Enum):
    """Возможные события."""
    START = "start"
    COMPLETE = "complete"
    FAIL = "fail"
    RETRY = "retry"

class SimpleFSM:
    def __init__(self):
        self.current_state = State.IDLE
        # Таблица переходов: (state, event) -> new_state
        self.transitions: Dict[tuple, State] = {
            (State.IDLE, Event.START): State.LOADING,
            (State.LOADING, Event.COMPLETE): State.SUCCESS,
            (State.LOADING, Event.FAIL): State.ERROR,
            (State.ERROR, Event.RETRY): State.LOADING,
            (State.SUCCESS, Event.START): State.LOADING,
        }
    
    def handle_event(self, event: Event) -> bool:
        """Обработать событие и перейти в новое состояние."""
        key = (self.current_state, event)
        
        if key not in self.transitions:
            print(f"❌ Переход невозможен: {self.current_state} + {event}")
            return False
        
        new_state = self.transitions[key]
        print(f"✓ Переход: {self.current_state.value}{new_state.value}")
        self.current_state = new_state
        return True

# Использование
fsm = SimpleFSM()
print(f"Начальное состояние: {fsm.current_state.value}")

fsm.handle_event(Event.START)      # idle → loading
fsm.handle_event(Event.COMPLETE)   # loading → success
fsm.handle_event(Event.START)      # success → loading
fsm.handle_event(Event.FAIL)       # loading → error
fsm.handle_event(Event.RETRY)      # error → loading
fsm.handle_event(Event.COMPLETE)   # loading → success
fsm.handle_event(Event.FAIL)       # ❌ Невозможно (success + fail = не определён)

Пример: Управление заказом в интернет-магазине

from enum import Enum

class OrderState(Enum):
    PENDING = "pending"          # Ожидание подтверждения
    CONFIRMED = "confirmed"      # Подтверждён
    SHIPPED = "shipped"          # Отправлен
    DELIVERED = "delivered"      # Доставлен
    CANCELLED = "cancelled"      # Отменён

class OrderEvent(Enum):
    CONFIRM = "confirm"
    SHIP = "ship"
    DELIVER = "deliver"
    CANCEL = "cancel"
    REFUND = "refund"

class Order:
    def __init__(self, order_id: str):
        self.order_id = order_id
        self.state = OrderState.PENDING
        self.history = [(OrderState.PENDING, None)]
    
    def handle_event(self, event: OrderEvent) -> bool:
        """Обработать событие."""
        transitions = {
            (OrderState.PENDING, OrderEvent.CONFIRM): OrderState.CONFIRMED,
            (OrderState.PENDING, OrderEvent.CANCEL): OrderState.CANCELLED,
            (OrderState.CONFIRMED, OrderEvent.SHIP): OrderState.SHIPPED,
            (OrderState.CONFIRMED, OrderEvent.CANCEL): OrderState.CANCELLED,
            (OrderState.SHIPPED, OrderEvent.DELIVER): OrderState.DELIVERED,
            (OrderState.SHIPPED, OrderEvent.CANCEL): OrderState.CANCELLED,  # Отмена при доставке
            (OrderState.CANCELLED, OrderEvent.REFUND): OrderState.PENDING,  # Возврат
        }
        
        key = (self.state, event)
        if key not in transitions:
            return False
        
        old_state = self.state
        self.state = transitions[key]
        self.history.append((self.state, event))
        print(f"Заказ {self.order_id}: {old_state.value}{self.state.value}")
        return True

# Сценарий 1: Успешная доставка
order1 = Order("ORD-001")
order1.handle_event(OrderEvent.CONFIRM)
order1.handle_event(OrderEvent.SHIP)
order1.handle_event(OrderEvent.DELIVER)
print(f"История: {[(s.value, e.value if e else None) for s, e in order1.history]}")

# Сценарий 2: Отмена перед доставкой
order2 = Order("ORD-002")
order2.handle_event(OrderEvent.CONFIRM)
order2.handle_event(OrderEvent.CANCEL)  # Отменили
order2.handle_event(OrderEvent.REFUND)   # Вернули
print(f"История: {[(s.value, e.value if e else None) for s, e in order2.history]}")

Более сложный пример: Telegram Bot FSM

from enum import Enum
from typing import Optional, Dict, List

class UserState(Enum):
    START = "start"
    CHOOSING_PRODUCT = "choosing_product"
    ENTERING_QUANTITY = "entering_quantity"
    CHECKOUT = "checkout"
    PAYMENT = "payment"
    COMPLETED = "completed"
    CANCELLED = "cancelled"

class UserEvent(Enum):
    START_SHOPPING = "start_shopping"
    SELECT_PRODUCT = "select_product"
    ENTER_QUANTITY = "enter_quantity"
    GO_TO_CHECKOUT = "go_to_checkout"
    CONFIRM_PAYMENT = "confirm_payment"
    PAYMENT_SUCCESS = "payment_success"
    PAYMENT_FAILED = "payment_failed"
    CANCEL = "cancel"
    RETRY = "retry"

class UserFSM:
    def __init__(self, user_id: int):
        self.user_id = user_id
        self.state = UserState.START
        self.cart: List[Dict] = []
        self.current_quantity: Optional[int] = None
    
    def handle_event(self, event: UserEvent, **kwargs) -> bool:
        """Обработать событие с параметрами."""
        transitions = {
            (UserState.START, UserEvent.START_SHOPPING): UserState.CHOOSING_PRODUCT,
            (UserState.CHOOSING_PRODUCT, UserEvent.SELECT_PRODUCT): UserState.ENTERING_QUANTITY,
            (UserState.ENTERING_QUANTITY, UserEvent.ENTER_QUANTITY): UserState.CHOOSING_PRODUCT,
            (UserState.CHOOSING_PRODUCT, UserEvent.GO_TO_CHECKOUT): UserState.CHECKOUT,
            (UserState.CHECKOUT, UserEvent.CONFIRM_PAYMENT): UserState.PAYMENT,
            (UserState.PAYMENT, UserEvent.PAYMENT_SUCCESS): UserState.COMPLETED,
            (UserState.PAYMENT, UserEvent.PAYMENT_FAILED): UserState.CHECKOUT,
            (UserState.PAYMENT, UserEvent.RETRY): UserState.PAYMENT,
            (UserState.CHECKOUT, UserEvent.CANCEL): UserState.CANCELLED,
            (UserState.CHOOSING_PRODUCT, UserEvent.CANCEL): UserState.CANCELLED,
        }
        
        key = (self.state, event)
        if key not in transitions:
            print(f"❌ Невозможный переход: {self.state.value} + {event.value}")
            return False
        
        # Выполнить действие перед переходом
        self._on_event(event, **kwargs)
        
        # Перейти в новое состояние
        new_state = transitions[key]
        print(f"Пользователь {self.user_id}: {self.state.value}{new_state.value}")
        self.state = new_state
        return True
    
    def _on_event(self, event: UserEvent, **kwargs):
        """Выполнить действие при событии."""
        if event == UserEvent.SELECT_PRODUCT:
            product = kwargs.get('product')
            self.cart.append({"product": product})
            print(f"  → Добавлен товар: {product}")
        
        elif event == UserEvent.ENTER_QUANTITY:
            quantity = kwargs.get('quantity')
            self.current_quantity = quantity
            print(f"  → Количество: {quantity}")
        
        elif event == UserEvent.PAYMENT_SUCCESS:
            print(f"  → Платёж успешен! Товары: {self.cart}")
            self.cart = []

# Использование
user = UserFSM(user_id=123)
user.handle_event(UserEvent.START_SHOPPING)
user.handle_event(UserEvent.SELECT_PRODUCT, product="Laptop")
user.handle_event(UserEvent.ENTER_QUANTITY, quantity=1)
user.handle_event(UserEvent.SELECT_PRODUCT, product="Mouse")
user.handle_event(UserEvent.ENTER_QUANTITY, quantity=2)
user.handle_event(UserEvent.GO_TO_CHECKOUT)
user.handle_event(UserEvent.CONFIRM_PAYMENT)
user.handle_event(UserEvent.PAYMENT_SUCCESS)
print(f"Финальное состояние: {user.state.value}")

Диаграмма состояний (State Diagram)

Пример: Медиа-плеер

         ┌─────────────────────┐
         │      STOPPED        │
         └────────┬────────────┘
                  │
              play│ resume
                  ↓
         ┌─────────────────────┐
         │      PLAYING        │<─────┐
         └────────┬────────────┘      │
                  │                   │
               pause                  │
                  ↓                   │
         ┌─────────────────────┐      │
         │      PAUSED         │      │
         └────────┬────────────┘      │
                  │                   │
            resume│                   │
                  └───────────────────┘
                  
                  stop (из любого состояния)
                    ↓
         ┌─────────────────────┐
         │      STOPPED        │
         └─────────────────────┘

Применение FSM в реальных системах

# 1. Workflow процессы
# Согласование документов: draft → submitted → approved → published

# 2. Игры
# Player states: idle → running → jumping → falling → idle

# 3. Сетевые протоколы
# TCP states: LISTEN → SYN_RECEIVED → ESTABLISHED → FIN_WAIT → CLOSED

# 4. Парсеры
# Лексический анализ, синтаксический анализ

# 5. Контроллеры (MVC)
# Управление состоянием приложения

# 6. Тестирование
# Model-based testing использует FSM

Преимущества FSM

✓ Ясность логики
  - Явно определены все допустимые переходы
  - Легко понять поведение системы
  - Нет "сюрпризов" и скрытых состояний

✓ Недопустимые состояния невозможны
  - Система не может перейти в некорректное состояние
  - Ошибки выявляются на этапе проектирования

✓ Тестирование
  - Легко покрыть все состояния и переходы
  - Можно сгенерировать все возможные сценарии

✓ Документирование
  - Диаграмма состояний это сама себя документирует
  - Код соответствует требованиям

Недостатки

❌ Взрывчатость состояний
  - Если параметров много → состояний может быть очень много
  - 10 булевых флагов = 2^10 = 1024 состояния
  - Решение: иерархические автоматы (Statecharts)

❌ Жёсткость
  - Тяжело добавить новые переходы
  - Нужно пересматривать всю таблицу переходов
  - Решение: использовать конфигурацию вместо hardcode

Ключевые моменты

  • FSM имеет конечное число состояний
  • Переходы зависят от текущего состояния и события
  • Недопустимые переходы должны быть явно запрещены
  • Диаграммы состояний помогают визуализировать логику
  • Используется везде: игры, протоколы, workflow, парсеры
  • Тестировать FSM проще чем тестировать if-else спагетти