aiogram异步Telegram Bot开发:循环中获取用户输入的问题及报错解决
解决aiogram异步机器人中循环等待用户输入的问题
错误原因分析
- 变量类型错误:你将
new_answer初始化为Playgame.number(这是State类的实例),执行int(new_answer)时自然会抛出类型错误,因为State对象无法转换为整数。 - 数据获取错误:在
process_number函数中,await state.get_state()获取的是当前状态的标识符(如字符串"Playgame:number"),不是用户输入的数字,正确的做法是用await state.get_data()提取之前通过state.update_data存储的内容。 - 核心逻辑问题:原代码中的
for循环会异步执行完所有100次迭代,一次性发送所有问题,不会等待用户输入——这是因为aiogram是事件驱动模型,同步for循环无法适配异步交互场景。
解决方案
方案一:使用state.wait_for()在循环中直接等待输入
这种方式代码简洁,适合简单的循环交互场景:
from aiogram import Router, F from aiogram.filters.state import State, StatesGroup from aiogram.fsm.context import FSMContext from aiogram.types import Message import random router = Router() # 假设你已经定义了kb.gamekeyboard class Playgame(StatesGroup): number = State() @router.message(F.text == "Let's play!") async def nice(message: Message, state: FSMContext): await state.set_state(Playgame.number) numbers = [] user_score = 0 for i in range(1, 101): # 生成不重复的计算结果 num1 = random.randint(1, 10) num2 = random.randint(1, 10) result = num1 + num2 while result in numbers: num1 = random.randint(1, 10) num2 = random.randint(1, 10) result = num1 + num2 numbers.insert(0, result) # 发送问题 await message.answer(f'Game started at {i}) {num1}+{num2}=__?', reply_markup=kb.gamekeyboard) # 等待用户输入数字(用正则过滤非数字输入) user_input_msg = await state.wait_for(F.text.regexp(r'^\d+$')) try: new_answer = int(user_input_msg.text) except ValueError: await message.reply("请输入有效的数字!") continue # 判断答案并更新分数 if new_answer == result: user_score += 1 await message.reply(f"Yes right! Your score: {user_score}") else: user_score -= 1 await message.reply(f"No that is mistake! Next question! Your score: {user_score}") # 游戏结束,清除状态 await state.clear() await message.answer(f"Game over! Final score: {user_score}")
方案二:用FSM状态流转管理游戏流程
这种方式更符合aiogram的事件驱动模型,便于处理复杂场景(如中途退出、保存进度):
from aiogram import Router, F from aiogram.filters.state import State, StatesGroup from aiogram.fsm.context import FSMContext from aiogram.types import Message import random router = Router() # 假设你已经定义了kb.gamekeyboard class Playgame(StatesGroup): waiting_answer = State() game_running = State() @router.message(F.text == "Let's play!") async def start_game(message: Message, state: FSMContext): # 初始化游戏数据 await state.set_state(Playgame.game_running) await state.update_data(numbers=[], user_score=0, current_round=1) # 发送第一个问题 await send_next_question(message, state) async def send_next_question(message: Message, state: FSMContext): data = await state.get_data() current_round = data["current_round"] # 判断是否结束游戏 if current_round > 100: await state.clear() await message.answer(f"Game over! Final score: {data['user_score']}") return # 生成不重复的计算结果 num1 = random.randint(1, 10) num2 = random.randint(1, 10) result = num1 + num2 numbers = data["numbers"] while result in numbers: num1 = random.randint(1, 10) num2 = random.randint(1, 10) result = num1 + num2 numbers.insert(0, result) # 更新游戏状态,进入等待答案状态 await state.update_data( numbers=numbers, current_result=result, current_round=current_round + 1 ) await state.set_state(Playgame.waiting_answer) await message.answer(f'Game started at {current_round}) {num1}+{num2}=__?', reply_markup=kb.gamekeyboard) @router.message(Playgame.waiting_answer, F.text.regexp(r'^\d+$')) async def process_answer(message: Message, state: FSMContext): data = await state.get_data() try: new_answer = int(message.text) except ValueError: await message.reply("请输入有效的数字!") return # 计算分数 result = data["current_result"] user_score = data["user_score"] if new_answer == result: user_score += 1 await message.reply(f"Yes right! Your score: {user_score}") else: user_score -= 1 await message.reply(f"No that is mistake! Next question! Your score: {user_score}") # 更新分数并发送下一个问题 await state.update_data(user_score=user_score) await send_next_question(message, state) # 处理无效输入 @router.message(Playgame.waiting_answer) async def invalid_answer(message: Message): await message.reply("请输入有效的数字!")
关键说明
- 两种方案都解决了原代码中
for循环不等待用户输入的问题,适配aiogram的异步事件模型。 - 增加了非数字输入的处理逻辑,避免程序崩溃。
- 修正了原代码中重复结果的生成逻辑,确保每轮问题的结果不重复。
内容的提问来源于stack exchange,提问作者JohnyBi python beginner
相关产品推荐
相关产品推荐

