FSM
Telegram-бот: машина состояний
● интерактивный урок

FSM без 49 страниц: понять за 10 минут

Главная идея простая: бот должен помнить на каком шаге находится пользователь и что он уже ввёл раньше.

🤖 Concert Bot
/start
Введите ваше имя
Алексей
Теперь введите возраст
17
Выберите пол
Что видит программа
state = choose_gender
data = { name: "Алексей", age: 17 }
01 · зачем это нужно

Одно сообщение — разный смысл

Сам текст сообщения не всегда говорит программе, что с ним делать. Нужен контекст.

Попробуй переключить этап

17
Сейчас бот ждёт возраст → «17» считается возрастом.

Что добавляет FSM?

Без FSM бот видит только отдельные сообщения:

"Алексей"
"17"
"Мужской"

С FSM к каждому сообщению добавляется контекст:

input_name → "Алексей" → имя
input_age → "17" → возраст
choose_gender → кнопка → пол

STATE = где мы сейчас

input_age

Отвечает на вопрос: что пользователь должен сделать прямо сейчас?

DATA = что уже запомнили

{ name: "Алексей" }

Отвечает на вопрос: что пользователь уже ввёл на предыдущих шагах?

02 · вся машина целиком

FSM — это маршрут из состояний

Правильный ввод переводит дальше. Ошибка оставляет пользователя на текущем шаге.
input_nameждём имя
→имя корректно
input_ageждём возраст
→возраст корректен
choose_genderждём кнопку
→пол выбран
confirmationпроверяем данные
/start → input_name → input_age → choose_gender → confirmation
03 · главное

Пройди регистрацию сам

Слева — Telegram. Справа — то, что в этот же момент хранит и запускает программа.
B
Concert Botучебный бот

🧠 Память бота

Переключи пользователя — у каждого своя FSM.
Текущее состояние
—
Сохранённые данные
data
пока пусто
Какой обработчик сработает
Сначала отправьте /start
FSM ещё не запущена. Нажмите «Отправить /start».
04 · код без лишнего

Почти каждый шаг FSM — 5 действий

Это шаблон, который стоит запомнить. Конкретные названия состояний могут быть другими.
1
Получили вводБерём текст или callback.value = message.text
2
ПроверилиПодходит ли значение?if ошибка: ...
3
СохранилиЗапомнили результат шага.state.add_data(...)
4
Перешли дальшеСменили состояние.state.set(...)
5
Сказали, что дальшеПросим следующий ввод.bot.send_message(...)

Минимальный пример обработчика возраста

# работает только на этапе ввода возраста
@bot.message_handler(state=RegistrationStates.input_age, content_types=["text"])
def process_state_input_age(message, state):
    try:
        age = int(message.text.strip())
    except:
        bot.send_message(message.chat.id, "Введите возраст числом")
        return

    if age < 13 or age > 100:
        bot.send_message(message.chat.id, "Возраст должен быть от 13 до 100")
        return

    state.add_data(age=age)
    state.set(RegistrationStates.choose_gender)
    bot.send_message(message.chat.id, "Выберите пол")
05 · почему return важен

Ошибка не двигает пользователя дальше

❌ Пользователь пишет «Привет»

state = input_age

Преобразовать в int нельзя.

→

✅ Бот отвечает об ошибке

return

Функция остановилась, поэтому state остаётся input_age. Можно попробовать снова.

06 · как бот выбирает функцию

Состояние работает как маршрутизатор

Обычный текстовый handler может реагировать на любой текст. Handler с state=... — только на нужном этапе.
state = input_name
state = input_age
state = choose_gender
→
process_state_input_name()
process_state_input_age()
process_state_choose_gender()
07 · две тонкости

У каждого пользователя — своя память

👥 Маша и Петя могут быть на разных шагах

Один бот одновременно ведёт много независимых диалогов.

👩
Машаstate = input_age
👨
Петяstate = input_name

⚠️ StateMemoryStorage — временная память

В учебном проекте состояние хранится в оперативной памяти. Перезапустили Python-программу — состояния и данные исчезли.

StateMemoryStorage()
# удобно для обучения, но не для постоянного хранения
08 · шпаргалка

4 вопроса перед каждым новым состоянием

вопрос 1

Где пользователь сейчас?

input_age
вопрос 2

Что он должен отправить?

Число
вопрос 3

Что нужно сохранить?

age
вопрос 4

Какое состояние следующее?

choose_gender
09 · проверка

Понял ли ты FSM?

Нажимай ответ — результат появится сразу.

1. Что хранит state?

2. Что делает state.add_data(age=17)?

3. Возраст введён неверно. Что лучше сделать?

4. Почему для Inline-кнопки нужен callback handler?

10 · если хочешь потренироваться

Три задания по нарастающей

Легко

Доделать confirmation

Accept → завершить регистрацию и удалить state. Error → начать заново.

state.delete()
Средне

Добавить город

Новое состояние между возрастом и выбором пола.

input_city = State()
Сложнее

Исправлять только одно поле

Из confirmation возвращаться именно к имени, возрасту или полу, а не начинать всё заново.

confirmation → input_age

Если запомнить только 3 вещи

1. Stateгде пользователь сейчас
2. Dataчто он уже ввёл
3. Transitionсохранили → state.set(next)
Скопировано