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

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))

关键改动说明

  1. 用asyncio.Event替代共享变量:每个/test命令调用都会创建独立的stop_event,避免多个调用之间的状态干扰。
  2. 回调逻辑调整:按钮回调中调用stop_event.set()来通知主循环停止,而非修改共享的实例变量。
  3. 循环终止条件:主循环中通过stop_event.is_set()判断是否需要终止,确保每次命令调用的循环逻辑独立执行。

内容的提问来源于stack exchange,提问作者syrok

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 14:22:08