Ответ
FSM (Finite State Machine, или конечный автомат) в aiogram — это механизм для управления состоянием пользователя в диалоге. Он необходим для создания многошаговых сценариев, таких как регистрация, анкетирование, оформление заказа или любая другая последовательность действий, где боту нужно запоминать предыдущие ответы пользователя.
Без FSM бот не помнит контекст: каждый новый handler обрабатывает сообщение независимо. FSM позволяет "вести" пользователя по заранее определенному сценарию, переключая его из одного состояния в другое.
Пример: Анкетирование пользователя
from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import State, StatesGroup
# 1. Определяем состояния
class UserPoll(StatesGroup):
name = State() # Состояние для ожидания имени
age = State() # Состояние для ожидания возраста
feedback = State() # Состояние для ожидания отзыва
# ... (инициализация бота и диспетчера)
# 2. Вход в сценарий (установка первого состояния)
@dp.message_handler(commands=['poll'])
async def start_poll(message: types.Message):
await UserPoll.name.set() # Устанавливаем состояние 'name'
await message.answer("Как вас зовут?")
# 3. Обработка ответа в состоянии 'name'
@dp.message_handler(state=UserPoll.name)
async def process_name(message: types.Message, state: FSMContext):
async with state.proxy() as data: # Сохраняем данные в FSMContext
data['name'] = message.text
await UserPoll.next() # Переключаемся на следующее состояние ('age')
await message.answer("Сколько вам лет?")
# 4. Обработка ответа в состоянии 'age' и завершение
@dp.message_handler(state=UserPoll.age)
async def process_age(message: types.Message, state: FSMContext):
# ... (сохранение возраста)
await state.finish() # Завершаем сценарий и сбрасываем состояние
await message.answer("Спасибо за участие!")
Ключевые преимущества:
- Структурированная логика: Код для каждого шага диалога изолирован в своем
handler. - Хранение данных:
FSMContextпредоставляет временное хранилище для данных, собранных в ходе диалога. - Контроль диалога: Позволяет создавать нелинейные сценарии с ветвлениями и возвратами.
Ответ 18+ 🔞
О, смотри-ка, что у нас тут! Конечный автомат, блядь, в aiogram! Ну это ж такая штука, чтобы бот не был как та мартышка, которая всё забывает через пять секунд. Без него твой бот — как тот мужик с похмелья: спросил имя, повернулся, и уже нихуя не помнит, кто ты такой.
Представь, ты пытаешься у пользователя анкету собрать. Без FSM это выглядит так:
Пользователь: /poll
Бот: Как вас зовут?
Пользователь: Василий
Бот: О, привет! И... э... нахуя ты мне имя сказал? — потому что следующий хэндлер про возраст уже понятия не имеет, что было до него. Пиздец, а не диалог.
А с FSM — это как вести пользователя за ручку по чёткому сценарию. Типа: "Стой тут, не ёрзай, сейчас имя спрошу... Запомнил. А теперь, сука, возраст давай".
Вот смотри, как это по-человечески, с состоянием, делается:
from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import State, StatesGroup
# 1. Это как объявить план допроса, этапы
class UserPoll(StatesGroup):
name = State() # Ждём, пока назовётся
age = State() # Ждём, пока сознается в годах
feedback = State() # Ждём, пока выскажется
# ... (тут бота заводишь как обычно)
# 2. Начало спектакля. Пользователь команду дал.
@dp.message_handler(commands=['poll'])
async def start_poll(message: types.Message):
await UserPoll.name.set() # Ставим его в состояние "допроса по имени"
await message.answer("Ну-ка, падаль, как звать-то?")
# 3. Ловим ответ именно в состоянии 'name'. Уже контекст есть!
@dp.message_handler(state=UserPoll.name)
async def process_name(message: types.Message, state: FSMContext):
async with state.proxy() as data: # Это типа временная папка "Дело №..."
data['name'] = message.text # Пишем имя в дело
await UserPoll.next() # Щёлкаем его на следующий этап — возраст
await message.answer(f"Так, {message.text}, я запомнил. Теперь годков сколько накопил?")
# 4. А вот тут он уже в состоянии 'age' ловится
@dp.message_handler(state=UserPoll.age)
async def process_age(message: types.Message, state: FSMContext):
# ... (тут возраст в то же 'data' пихаешь)
await state.finish() # Всё, спектакль окончен, состояние обнуляется
await message.answer("Вот и славно, свободен. Данные твои... куда-нибудь денутся.")
И в чём, блядь, магия-то?
- Порядок в голове: Каждый шаг диалога сидит в своём углу и не лезет в чужой. За имя отвечает один хэндлер, за возраст — другой. Красота, ёпта!
- Память, как у слона:
FSMContext— это такая временная памятная записка, куда ты можешь писать всё, что пользователь наговорил, пока сценарий идёт. Потом всё это разом вытащить и использовать. - Власть над диалогом: Хочешь — вперёд гони (
next()), хочешь — назад отправь (previous()), хочешь — нахуй сбрось (finish()). Полный контроль, как в хорошем фильме про гипноз.
Короче, если делаешь что-то сложнее, чем "привет-пока", без FSM ты просто мудак, который обрекает себя на ад из костылей и глобальных переменных. Не будь мудаком.