Pycord机器人Slash命令Embed第二次执行冻结问题求助
问题:Discord Slash命令Embed更新异常(首次正常,后续冻结)
现象描述
首次运行/test命令时,Embed每2秒更新一次,按钮的label和custom_id从x1递增到x99;点击按钮可触发回调函数,执行逻辑并停止主循环,一切正常。但第二次及之后运行该命令时,Embed会冻结在x1状态,不再更新,点击按钮也无任何响应。
问题复现代码
test.py
import asyncio from discord.ui import Button, View import discord from discord.commands import slash_command from discord.ext import commands class Test(commands.Cog): def __init__(self, bot): self.bot = bot self.stop_loop = False @slash_command(name='test', description='') async def run(self, ctx): async def button_callback(interaction): self.stop_loop = True embed = discord.Embed( description=f"stop function", ) await interaction.response.edit_message(embed=embed, view=None) return button = Button(custom_id=f"1", label=f'x1', style=discord.ButtonStyle.blurple) button.callback = button_callback my_view = View() my_view.add_item(button) embed = discord.Embed( title="some title", ) sent_embed = await ctx.respond(embed=embed, view=my_view, ephemeral=True) await asyncio.sleep(2) for i in range(2, 100): if self.stop_loop: return button = Button(custom_id=f"{i}", label=f'x{i}', style=discord.ButtonStyle.blurple) button.callback = button_callback my_view = View() my_view.add_item(button) embed = discord.Embed( title="some title", ) await sent_embed.edit_original_response(embed=embed, view=my_view) await asyncio.sleep(2) def setup(bot): bot.add_cog(Test(bot))
main.py
from discord.ext import commands import discord import os from tools.config import TOKEN intents = discord.Intents.default() intents.members = True client = commands.Bot(intents=intents, command_prefix = "!") for f in os.listdir("./cogs"): if f.endswith(".py"): client.load_extension("cogs." + f[:-3]) client.run(TOKEN)
环境信息
- py-cord==2.4.1
- Python 3.10
- Discord Cogs架构
问题根源
Test Cog中的self.stop_loop是类实例的共享变量,第一次点击按钮后该变量被设为True,后续所有/test命令调用时,都会读取到这个True值,直接跳过循环逻辑,导致Embed停留在初始的x1状态;同时共享状态也会导致多个命令调用互相干扰,按钮回调无法正常触发预期逻辑。
解决方案
将共享的self.stop_loop替换为每个命令调用独立的异步事件(asyncio.Event),确保每次命令调用的状态互不影响。
修改后的test.py代码
import asyncio from discord.ui import Button, View import discord from discord.commands import slash_command from discord.ext import commands class Test(commands.Cog): def __init__(self, bot): self.bot = bot @slash_command(name='test', description='') async def run(self, ctx): # 每个命令调用创建独立的Event,替代共享的stop_loop stop_event = asyncio.Event() async def button_callback(interaction): # 设置事件通知循环停止 stop_event.set() embed = discord.Embed(description=f"stop function") await interaction.response.edit_message(embed=embed, view=None) # 初始化按钮和视图 button = Button(custom_id="1", label='x1', style=discord.ButtonStyle.blurple) button.callback = button_callback my_view = View() my_view.add_item(button) embed = discord.Embed(title="some title") sent_embed = await ctx.respond(embed=embed, view=my_view, ephemeral=True) await asyncio.sleep(2) for i in range(2, 100): # 检查事件是否被触发,是则终止循环 if stop_event.is_set(): return # 更新按钮和视图 button = Button(custom_id=f"{i}", label=f'x{i}', style=discord.ButtonStyle.blurple) button.callback = button_callback my_view = View() my_view.add_item(button) await sent_embed.edit_original_response(embed=embed, view=my_view) await asyncio.sleep(2) def setup(bot): bot.add_cog(Test(bot))
关键改动说明
- 用asyncio.Event替代共享变量:每个
/test命令调用都会创建独立的stop_event,避免多个调用之间的状态干扰。 - 回调逻辑调整:按钮回调中调用
stop_event.set()来通知主循环停止,而非修改共享的实例变量。 - 循环终止条件:主循环中通过
stop_event.is_set()判断是否需要终止,确保每次命令调用的循环逻辑独立执行。
内容的提问来源于stack exchange,提问作者syrok
相关产品推荐
相关产品推荐

