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

aiogram异步Telegram Bot开发:循环中获取用户输入的问题及报错解决

解决aiogram异步机器人中循环等待用户输入的问题

错误原因分析

  1. 变量类型错误:你将new_answer初始化为Playgame.number(这是State类的实例),执行int(new_answer)时自然会抛出类型错误,因为State对象无法转换为整数。
  2. 数据获取错误:在process_number函数中,await state.get_state()获取的是当前状态的标识符(如字符串"Playgame:number"),不是用户输入的数字,正确的做法是用await state.get_data()提取之前通过state.update_data存储的内容。
  3. 核心逻辑问题:原代码中的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 15:54:57