如何在pyTelegramBotAPI的FSM状态机中从函数返回数据
问题:如何从pyTelegramBotAPI的FSM状态函数中提取用户数据用于后续处理?
我在使用pyTelegramBotAPI的有限状态机(FSM)时遇到了问题。我基于官方的自定义状态示例代码进行修改,希望在ready_for_answer函数中获取用户输入的姓名(name)、姓氏(surname)和年龄(age),并将这些数据传递出去进行后续业务处理。通常我会直接调用返回这些值的函数,但不清楚在当前的FSM代码结构下该如何实现。
我现有的代码框架如下:
import telebot from telebot import custom_filters from telebot.handler_backends import State, StatesGroup from telebot.storage import StateMemoryStorage state_storage = StateMemoryStorage() bot = telebot.TeleBot("TOKEN", state_storage=state_storage) class MyStates(StatesGroup): name = State() surname = State() age = State() @bot.message_handler(commands=['start']) def start_ex(message): bot.set_state(message.from_user.id, MyStates.name, message.chat.id) bot.send_message(message.chat.id, 'Hi, write me a name') @bot.message_handler(state="*", commands=['cancel']) def any_state(message): bot.send_message(message.chat.id, "Your state was cancelled.") bot.delete_state(message.from_user.id, message.chat.id) @bot.message_handler(state=MyStates.name) def name_get(message): bot.send_message(message.chat.id, 'Now write me a surname') bot.set_state(message.from_user.id, MyStates.surname, message.chat.id) with bot.retrieve_data(message.from_user.id, message.chat.id) as data: data['name'] = message.text @bot.message_handler(state=MyStates.surname) def ask_age(message): bot.send_message(message.chat.id, "What is your age?") bot.set_state(message.from_user.id, MyStates.age, message.chat.id) with bot.retrieve_data(message.from_user.id, message.chat.id) as data: data['surname'] = message.text # 我希望从这个函数返回姓名、姓氏和年龄用于后续处理 @bot.message_handler(state=MyStates.age, is_digit=True) def ready_for_answer(message): with bot.retrieve_data(message.from_user.id, message.chat.id) as data: msg = ("Ready, take a look:\n<b>" f"Name: {data['name']}\n" f"Surname: {data['surname']}\n" f"Age: {message.text}</b>") bot.send_message(message.chat.id, msg, parse_mode="html") bot.delete_state(message.from_user.id, message.chat.id) @bot.message_handler(state=MyStates.age, is_digit=False) def age_incorrect(message): bot.send_message(message.chat.id, 'Looks like you are submitting a string in the field age. Please enter a number') bot.add_custom_filter(custom_filters.StateFilter(bot)) bot.add_custom_filter(custom_filters.IsDigitFilter()) bot.infinity_polling(skip_pending=True)
解决方案
要实现将用户数据传递到后续处理的需求,你可以按以下方式修改代码:
修改后的完整代码
import telebot from telebot import custom_filters from telebot.handler_backends import State, StatesGroup from telebot.storage import StateMemoryStorage state_storage = StateMemoryStorage() bot = telebot.TeleBot("TOKEN", state_storage=state_storage) class MyStates(StatesGroup): name = State() surname = State() age = State() # ---------------------- 后续处理函数示例 ---------------------- def process_user_data(name, surname, age): """这里是你的后续业务逻辑,替换成实际需求即可""" print(f"处理用户数据:姓名={name},姓氏={surname},年龄={age}") # 示例:保存到数据库、调用API等操作 # save_to_database(name, surname, age) # ----------------------------------------------------------- @bot.message_handler(commands=['start']) def start_ex(message): bot.set_state(message.from_user.id, MyStates.name, message.chat.id) bot.send_message(message.chat.id, 'Hi, write me a name') @bot.message_handler(state="*", commands=['cancel']) def any_state(message): bot.send_message(message.chat.id, "Your state was cancelled.") bot.delete_state(message.from_user.id, message.chat.id) @bot.message_handler(state=MyStates.name) def name_get(message): bot.send_message(message.chat.id, 'Now write me a surname') bot.set_state(message.from_user.id, MyStates.surname, message.chat.id) with bot.retrieve_data(message.from_user.id, message.chat.id) as data: data['name'] = message.text @bot.message_handler(state=MyStates.surname) def ask_age(message): bot.send_message(message.chat.id, "What is your age?") bot.set_state(message.from_user.id, MyStates.age, message.chat.id) with bot.retrieve_data(message.from_user.id, message.chat.id) as data: data['surname'] = message.text @bot.message_handler(state=MyStates.age, is_digit=True) def ready_for_answer(message): with bot.retrieve_data(message.from_user.id, message.chat.id) as data: # 将年龄存入状态存储的data字典 data['age'] = message.text # 拼接回复消息并发送 msg = ("Ready, take a look:\n<b>" f"Name: {data['name']}\n" f"Surname: {data['surname']}\n" f"Age: {data['age']}</b>") bot.send_message(message.chat.id, msg, parse_mode="html") # 调用后续处理函数,传递收集到的所有数据 process_user_data(data['name'], data['surname'], data['age']) # 完成数据收集后删除状态 bot.delete_state(message.from_user.id, message.chat.id) @bot.message_handler(state=MyStates.age, is_digit=False) def age_incorrect(message): bot.send_message(message.chat.id, 'Looks like you are submitting a string in the field age. Please enter a number') bot.add_custom_filter(custom_filters.StateFilter(bot)) bot.add_custom_filter(custom_filters.IsDigitFilter()) bot.infinity_polling(skip_pending=True)
关键说明
- 统一存储数据:在
ready_for_answer中把用户输入的age也存入状态存储的data字典,确保所有字段都被统一管理。 - 定义后续处理函数:创建
process_user_data函数作为业务处理入口,你可以根据实际需求修改函数逻辑(比如保存到数据库、调用外部API等)。 - 直接传递数据:在
ready_for_answer中直接调用处理函数,将name、surname、age作为参数传入,完成数据的后续流转。 - 状态清理:在完成数据处理后再调用
bot.delete_state,确保数据在处理前不会被提前清除。
如果需要在其他地方复用这些数据,也可以通过bot.retrieve_data(user_id, chat_id)从状态存储中读取,但需要注意状态是否已被删除(若需要长期存储,建议使用数据库而非临时状态存储)。
内容的提问来源于stack exchange,提问作者Alexandr Gusak
相关产品推荐
相关产品推荐

