You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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)

关键说明

  1. 统一存储数据:在ready_for_answer中把用户输入的age也存入状态存储的data字典,确保所有字段都被统一管理。
  2. 定义后续处理函数:创建process_user_data函数作为业务处理入口,你可以根据实际需求修改函数逻辑(比如保存到数据库、调用外部API等)。
  3. 直接传递数据:在ready_for_answer中直接调用处理函数,将name、surname、age作为参数传入,完成数据的后续流转。
  4. 状态清理:在完成数据处理后再调用bot.delete_state,确保数据在处理前不会被提前清除。

如果需要在其他地方复用这些数据,也可以通过bot.retrieve_data(user_id, chat_id)从状态存储中读取,但需要注意状态是否已被删除(若需要长期存储,建议使用数据库而非临时状态存储)。

内容的提问来源于stack exchange,提问作者Alexandr Gusak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 13:50:25