discord.py如何在命令内部重启自身命令(无需重启机器人)
故障原因
代码存在两个核心问题导致逻辑不触发:
msg.content.lower是字符串的小写转换方法本身,你没有加()调用它,拿到的是方法对象,永远不可能和元组里的"y"/"yes"字符串匹配,判断恒为False,所以永远走else分支返回Bye。- Discord.py没有
get_invoke这个内置方法,你拿不到正确的命令对象,就算前面的判断通过,这行代码也会抛出异常。 - 你贴的代码还有缩进错误,函数内第一行
await ctx.send没有和其他代码对齐,实际运行会直接抛缩进语法错误,属于粘贴时的排版问题。
实现方案
优先用循环实现,没有递归栈溢出风险,稳定性最高:
import asyncio # 计时要用到asyncio的sleep,不要漏导 from discord.ext import commands # 对应你自己写的Cog类名 class PomodoroCog(commands.Cog): def __init__(self, client): self.client = client @commands.command(name='p_start') async def timer(self, ctx): while True: await ctx.send("Restart the pomodoro? Input y/yes to confirm, other input to exit.") msg = await self.client.wait_for( "message", check=lambda m: m.author == ctx.author and m.channel.id == ctx.channel.id ) # 加()调用lower(),加strip()过滤用户不小心输入的前后空格 if msg.content.strip().lower() in ("y", "yes"): await ctx.send("Pomodoro restarted, start timing...") # 在这里写番茄钟核心逻辑,比如25分钟工作+5分钟休息 # 示例逻辑: await asyncio.sleep(25*60) await ctx.send("Work session finished, take a 5-minute break.") await asyncio.sleep(5*60) await ctx.send("Break finished.") # 核心逻辑跑完后会自动回到循环开头,再次询问是否重启 else: await ctx.send("Bye!") break
如果你一定要用命令内部重入调用的方式,写法如下,注意这种方式如果用户反复重启次数过多,会触发Python递归深度限制报错,不推荐长期使用:
@commands.command(name='p_start') async def timer(self, ctx): await ctx.send("Restart the pomodoro? Input y/yes to confirm, other input to exit.") msg = await self.client.wait_for( "message", check=lambda m: m.author == ctx.author and m.channel.id == ctx.channel.id ) if msg.content.strip().lower() in ("y", "yes"): # 正确获取命令对象的API是get_command cmd = self.client.get_command('p_start') # 用上下文的invoke方法调用,会正常走命令的检查、错误处理逻辑 await ctx.invoke(cmd) else: await ctx.send("Bye!")
补充提示:
wait_for可以加timeout参数设置等待用户输入的超时时间,避免用户无响应时命令一直挂着占资源,比如await self.client.wait_for(..., timeout=60)就是等60秒没输入就抛TimeoutError,自行捕获处理即可。
内容的提问来源于stack exchange,提问作者Sino
相关产品推荐
相关产品推荐

