discord.py 非Cog独立函数文件中wait_for为何无法捕获用户输入消息
故障根源定位
- 引用断裂:
anime.py内调用bot.wait_for时,当前文件作用域内无对应bot实例定义,也未从主入口导入,运行至该行直接触发NameError,无法进入等待消息流程。此前尝试替换为self.bot或client无效,是因为业务逻辑是独立异步函数,无类实例上下文,不存在self绑定对象。 - 配置缺失:原
wait_for调用未配置过滤规则与超时参数。即便bot引用修正,默认逻辑会捕获全频道、全用户的消息,甚至机器人自身发送的列表提示也会被判定为用户回应;未传入timeout参数时,代码中编写的asyncio.TimeoutError捕获分支永远不会触发,程序会陷入无限等待。 - 风险隐患:跨文件反向导入bot实例极易引发循环导入(主入口导入业务模块、业务模块反向导入主入口的bot对象),导致程序启动直接崩溃。
落地修改方案
采用参数传值替代跨文件反向导入,同时补充wait_for的必要配置,从根源解决消息捕获问题:
- 调整函数传参链路:主入口调用业务函数时,直接将自身初始化的bot实例作为参数传入,避免跨文件导入的循环依赖问题。
- 补充wait_for的过滤规则:仅接收与原命令同频道、由触发命令的同一用户发送的非机器人消息,过滤无效输入。
- 补充超时配置:设置60秒等待阈值,触发原代码中编写的超时取消逻辑。
修改后代码
主入口文件 main.py
import discord import asyncio from discord.ext import commands from anime import search_anime bot = commands.Bot(command_prefix="m.") TOKEN = "INSERT TOKEN HERE" @bot.event async def on_ready(): print("Connected to discord") @bot.command(name="searchanime", help="Searches through the MAL Database to find an anime. Requires a title to search") async def search(ctx, *, query): # 调用业务函数时传入当前bot实例 await search_anime(ctx, query, bot) bot.run(TOKEN)
业务逻辑文件 anime.py
import discord import requests import asyncio headers = { 'x-rapidapi-key': "2ed26cb89emsh2b7cb079ec42fd9p15290cjsne485ef05078a", 'x-rapidapi-host': "jikan1.p.rapidapi.com" } # 形参新增bot字段,接收主入口传入的机器人实例 async def search_anime(ctx, query, bot): url = "https://jikan1.p.rapidapi.com/search/anime" querystring = {"q": query, "format": "json"} response = requests.request("GET", url, headers=headers, params=querystring).json() response_list = [] for i in range(4): response_list.append(response["results"][i]) await ctx.send("Message 'm.(desired number)' without the parenthesis to select the anime you are looking for from this list") for i in range(len(response_list)): await ctx.send(f"{i+1}) {response_list[i]['title']}") # 定义消息校验规则 def check(message): return ( message.channel == ctx.channel and message.author == ctx.author and not message.author.bot ) try: # 传入校验规则与60秒超时阈值 msg = await bot.wait_for("message", check=check, timeout=60.0) await ctx.send(msg.content) except asyncio.TimeoutError: await ctx.send("Cancelling due to timeout")
补充提示:原代码中使用的同步
requests库会阻塞Discord的异步事件循环,生产环境建议替换为异步HTTP客户端如aiohttp,避免程序卡顿。
内容的提问来源于stack exchange,提问作者Shitij Govil
相关产品推荐
相关产品推荐

