Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. State и конечные автоматы
state_machine

State и конечные автоматы

Управление состоянием через объекты. Конечные автоматы (FSM). Библиотека transitions и state_machine.

State и конечные автоматы

State превращает условия в объекты. FSM превращает хаос в порядок.


#State: управление состоянием

State — поведенческий паттерн, позволяющий объекту изменять поведение при изменении внутреннего состояния через переходы между объектами состояний.

#Проблема: спагетти из условий

# ❌ ПЛОХО: Много if/elif для состояний class Order: def __init__(self): self.state = "new" def pay(self): if self.state == "new": self.state = "paid" print("Order paid") elif self.state == "paid": print("Already paid") elif self.state == "shipped": print("Cannot pay shipped order") elif self.state == "cancelled": print("Cannot pay cancelled order") else: raise ValueError(f"Unknown state: {self.state}") def ship(self): if self.state == "paid": self.state = "shipped" print("Order shipped") elif self.state == "shipped": print("Already shipped") elif self.state == "new": print("Cannot ship unpaid order") else: print(f"Cannot ship from {self.state}") def cancel(self): if self.state in ("new", "paid"): self.state = "cancelled" print("Order cancelled") elif self.state == "shipped": print("Cannot ship shipped order") else: print(f"Cannot cancel from {self.state}") # Проблема: # 1. Нарушен Open-Closed — добавление состояния требует изменения всех методов # 2. Условия размазаны по всем методам # 3. Трудно понять допустимые переходы

#Решение: State через классы

# ✅ ХОРОШО: Каждое состояние — класс from abc import ABC, abstractmethod class OrderState(ABC): @abstractmethod def pay(self, order: "Order"): pass @abstractmethod def ship(self, order: "Order"): pass @abstractmethod def cancel(self, order: "Order"): pass @property @abstractmethod def name(self) -> str: pass class NewState(OrderState): @property def name(self) -> str: return "new" def pay(self, order: "Order"): order.state = PaidState() print("Order paid") def ship(self, order: "Order"): print("Cannot ship unpaid order") def cancel(self, order: "Order"): order.state = CancelledState() print("Order cancelled") class PaidState(OrderState): @property def name(self) -> str: return "paid" def pay(self, order: "Order"): print("Already paid") def ship(self, order: "Order"): order.state = ShippedState() print("Order shipped") def cancel(self, order: "Order"): order.state = CancelledState() print("Order cancelled, refund initiated") class ShippedState(OrderState): @property def name(self) -> str: return "shipped" def pay(self, order: "Order"): print("Cannot pay shipped order") def ship(self, order: "Order"): print("Already shipped") def cancel(self, order: "Order"): print("Cannot cancel shipped order") class CancelledState(OrderState): @property def name(self) -> str: return "cancelled" def pay(self, order: "Order"): print("Cannot pay cancelled order") def ship(self, order: "Order"): print("Cannot ship cancelled order") def cancel(self, order: "Order"): print("Already cancelled") class Order: def __init__(self): self.state: OrderState = NewState() def pay(self): self.state.pay(self) def ship(self): self.state.ship(self) def cancel(self): self.state.cancel(self) # Использование order = Order() order.pay() # Order paid order.ship() # Order shipped order.cancel() # Cannot cancel shipped order

#FSM: конечный автомат

#Таблица переходов

# ✅ FSM через таблицу переходов from typing import Dict, Tuple, Optional class StateMachine: def __init__(self, initial_state: str): self._state = initial_state self._transitions: Dict[Tuple[str, str], str] = {} self._handlers: Dict[str, callable] = {} def add_transition(self, from_state: str, event: str, to_state: str, handler: callable = None): self._transitions[(from_state, event)] = to_state if handler: self._handlers[(from_state, event)] = handler def trigger(self, event: str) -> bool: key = (self._state, event) if key not in self._transitions: print(f"Invalid transition: {self._state} --{event}--> ?") return False new_state = self._transitions[key] print(f"{self._state} --{event}--> {new_state}") if key in self._handlers: self._handlers[key]() self._state = new_state return True @property def state(self) -> str: return self._state # Использование fsm = StateMachine("new") # Добавляем переходы fsm.add_transition("new", "pay", "paid") fsm.add_transition("new", "cancel", "cancelled") fsm.add_transition("paid", "ship", "shipped") fsm.add_transition("paid", "cancel", "cancelled") fsm.add_transition("shipped", "deliver", "delivered") fsm.add_transition("cancelled", "restore", "new") fsm.trigger("pay") # new --pay--> paid fsm.trigger("ship") # paid --ship--> shipped fsm.trigger("deliver") # shipped --deliver--> delivered

#FSM с данными

# ✅ FSM с контекстом from dataclasses import dataclass, field from typing import Any @dataclass class Transition: to_state: str handler: callable = None condition: callable = None class FSM: def __init__(self, initial_state: str): self._state = initial_state self._context: dict = {} self._transitions: Dict[str, Dict[str, Transition]] = {} def add_transition(self, from_state: str, event: str, to_state: str, handler: callable = None, condition: callable = None): if from_state not in self._transitions: self._transitions[from_state] = {} self._transitions[from_state][event] = Transition(to_state, handler, condition) def trigger(self, event: str, **data) -> bool: if self._state not in self._transitions: return False if event not in self._transitions[self._state]: return False transition = self._transitions[self._state][event] # Проверка условия if transition.condition and not transition.condition(self._context, data): print(f"Condition failed for {event}") return False # Обновление контекста self._context.update(data) # Выполнение перехода print(f"{self._state} --{event}--> {transition.to_state}") if transition.handler: transition.handler(self._context) self._state = transition.to_state return True @property def state(self) -> str: return self._state # Использование fsm = FSM("idle") def check_balance(ctx, data): return data.get("amount", 0) <= ctx.get("balance", 0) def deduct(ctx): ctx["balance"] -= ctx.get("amount", 0) print(f"Balance: ${ctx['balance']}") fsm.add_transition("idle", "withdraw", "processing", handler=deduct, condition=check_balance) fsm.add_transition("processing", "complete", "idle") fsm._context["balance"] = 100 fsm.trigger("withdraw", amount=50) # idle --withdraw--> processing, Balance: $50 fsm.trigger("complete") # processing --complete--> idle

#Библиотека transitions

# ✅ transitions — готовая FSM библиотека # pip install transitions from transitions import Machine class Order: states = ["new", "paid", "shipped", "delivered", "cancelled"] def __init__(self): self.machine = Machine( model=self, states=Order.states, initial="new", ) # Добавляем переходы self.machine.add_transition("pay", "new", "paid") self.machine.add_transition("ship", "paid", "shipped") self.machine.add_transition("deliver", "shipped", "delivered") self.machine.add_transition("cancel", ["new", "paid"], "cancelled") self.machine.add_transition("restore", "cancelled", "new") def on_enter_paid(self): print("Order paid, sending confirmation email") def on_enter_shipped(self): print("Order shipped, sending tracking number") def on_enter_delivered(self): print("Order delivered, marking complete") # Использование order = Order() print(order.state) # new order.pay() print(order.state) # paid order.ship() print(order.state) # shipped order.deliver() print(order.state) # delivered

#Практическое применение

#Состояние подключения

# ✅ Connection State Machine class ConnectionState: def connect(self, conn): pass def disconnect(self, conn): pass def send(self, conn, data): pass class Disconnected(ConnectionState): def connect(self, conn): conn.state = Connected() print("Connected") class Connected(ConnectionState): def disconnect(self, conn): conn.state = Disconnected() print("Disconnected") def send(self, conn, data): print(f"Sent: {data}") class Connection: def __init__(self): self.state: ConnectionState = Disconnected() def connect(self): self.state.connect(self) def disconnect(self): self.state.disconnect(self) def send(self, data): self.state.send(self, data) # Использование conn = Connection() conn.send("Hello") # Ничего (disconnected) conn.connect() # Connected conn.send("Hello") # Sent: Hello conn.disconnect() # Disconnected

#Игровой автомат

# ✅ Game State Machine from enum import Enum, auto class GameState(Enum): MENU = auto() PLAYING = auto() PAUSED = auto() GAME_OVER = auto() class Game: def __init__(self): self.state = GameState.MENU self.score = 0 def start(self): if self.state == GameState.MENU: self.state = GameState.PLAYING self.score = 0 print("Game started") else: print("Cannot start from this state") def pause(self): if self.state == GameState.PLAYING: self.state = GameState.PAUSED print("Game paused") else: print("Cannot pause now") def resume(self): if self.state == GameState.PAUSED: self.state = GameState.PLAYING print("Game resumed") else: print("Cannot resume now") def game_over(self): if self.state == GameState.PLAYING: self.state = GameState.GAME_OVER print(f"Game Over! Score: {self.score}") else: print("Cannot game over now") def restart(self): if self.state == GameState.GAME_OVER: self.state = GameState.MENU print("Back to menu") else: print("Cannot restart now") # Использование game = Game() game.start() # Game started game.pause() # Game paused game.resume() # Game resumed game.game_over() # Game Over! Score: 0 game.restart() # Back to menu

#Что дальше?

Изучите тему Strategy и Dependency Injection для семейства алгоритмов.

Далее: Strategy и Dependency Injection