Ответ
Управлять состоянием пользователя без FSM (Finite State Machine) можно, сохраняя его вручную в каком-либо хранилище. Это подходит для простых сценариев, где не требуется сложная логика переходов между состояниями.
Способы хранения состояния:
- Словарь в памяти (In-memory Dictionary): Подходит только для отладки. Данные теряются при перезапуске бота.
- Кэш (Redis): Быстрый и эффективный способ. Состояние хранится в виде пар
user_id:stateс возможностью установки времени жизни (TTL). - База данных (SQLite, PostgreSQL): Надёжный способ для хранения долгоживущих состояний и связанных с ними данных.
Пример на aiogram с хранением в словаре:
from aiogram import Bot, Dispatcher, types
# ВАЖНО: Этот способ не подходит для продакшена, т.к. данные теряются при перезапуске
user_states = {}
bot = Bot(token="YOUR_API_TOKEN")
dp = Dispatcher(bot)
# Шаг 1: Запускаем диалог и устанавливаем состояние
@dp.message_handler(commands=['register'])
async def start_registration(message: types.Message):
user_id = message.from_user.id
user_states[user_id] = "waiting_for_name"
await message.answer("Введите ваше имя:")
# Шаг 2: Обрабатываем сообщение в зависимости от текущего состояния
@dp.message_handler()
async def process_message(message: types.Message):
user_id = message.from_user.id
current_state = user_states.get(user_id)
if current_state == "waiting_for_name":
name = message.text
await message.answer(f"Отлично, {name}! Теперь введите ваш возраст.")
# Переводим пользователя в следующее состояние
user_states[user_id] = "waiting_for_age"
elif current_state == "waiting_for_age":
age = message.text
await message.answer(f"Регистрация завершена! Ваш возраст: {age}")
# Очищаем состояние после завершения диалога
del user_states[user_id]
Преимущества:
- Простота реализации для коротких диалогов.
- Полный контроль над логикой хранения.
Недостатки:
- Код быстро усложняется с ростом числа состояний.
- Требуется вручную реализовывать логику переходов и очистки состояний.
Для сложных ботов использование встроенных механизмов FSM (aiogram.fsm) является предпочтительным.
Ответ 18+ 🔞
А, ну это ж классика, блядь! Опять про эти ваши состояния пользователей без FSM. Ну слушай, сейчас разжуем, как это бывает в жизни, а не в этих ваших академических справочниках.
Представь себе, что ты — царь и бог своего маленького ботика. И тебе надо запомнить, на каком этапе диалога находится каждый юзверь. FSM — это как нанять строгого менеджера, который будет следить за всеми переходами по правилам. А без него — ты сам этот менеджер, сука, и всё на твоей совести.
Куда можно пихать эти состояния, чтобы не потерять?
- В память, в обычный словарик. Это как записывать на салфетке в баре. Перезапустил бота — и всё, пиздец, салфетку выкинули. Только для теста, когда по-быстрому надо проверить идею.
- В Redis. О, это уже серьёзно! Быстро, как удар током, и можно сделать так, чтобы запись сама сдохла через время (TTL). Идеально для временных диалогов.
- В нормальную базу данных (SQLite, Postgres). Это уже на века, блядь. Если твой диалог — это многоэтапный квест, а данные надо хранить дольше, чем память золотой рыбки.
Смотри, как это выглядит в коде на aiogram, если ты решил быть мазохистом и всё делать руками:
from aiogram import Bot, Dispatcher, types
# ВАЖНО: Это пиздец как ненадёжно для продакшена! Перезапустил — и все твои пользователи как будто только что с Марса прилетели.
user_states = {} # Вот наш "волшебный" словарик, где всё и хранится
bot = Bot(token="YOUR_API_TOKEN")
dp = Dispatcher(bot)
# Шаг 1: Юзер тыкает /register, а мы ему — развод
@dp.message_handler(commands=['register'])
async def start_registration(message: types.Message):
user_id = message.from_user.id
user_states[user_id] = "waiting_for_name" # Записали: "Вася, ждём имя, не пизди"
await message.answer("Введите ваше имя:")
# Шаг 2: А тут мы ловим все сообщения и смотрим — а не наш ли это клиент?
@dp.message_handler()
async def process_message(message: types.Message):
user_id = message.from_user.id
current_state = user_states.get(user_id) # Достаём из кармана записку: на каком он этапе?
if current_state == "waiting_for_name":
name = message.text
await message.answer(f"Отлично, {name}! Теперь введите ваш возраст.")
# Переключаем рычажок в голове пользователя на следующий этап
user_states[user_id] = "waiting_for_age"
elif current_state == "waiting_for_age":
age = message.text
await message.answer(f"Регистрация завершена! Ваш возраст: {age}")
# Всё, отжёг, стираем лапшу с ушей. Состояние можно удалять.
del user_states[user_id]
И что мы имеем в сухом остатке, ёпта?
Плюсы (их мало, но они есть):
- Для простого диалога из двух-трёх шагов — легко и быстро.
- Ты как бог контролируешь каждый чих. Хочешь — в кэш пиши, хочешь — в базу.
Минусы (их дохуя и они злые):
- Как только сценариев станет больше двух, твой код превратится в спагетти, которые даже макароны-монстр не распутает.
- Всю логику переходов, очистки и проверок ты пишешь сам. Забыл почистить состояние — получил пользователя, который вечно ждёт возраста. Пиздец.
Так что, если твой бот — это не просто одноразовая игрушка, а что-то посерьёзнее, лучше всё-таки использовать встроенные FSM (aiogram.fsm). Это как ехать на велосипеде с мотором, а не толкать его ногами в гору. Но если хочешь почувствовать себя настоящим страдальцем — welcome to the club, делай всё руками.