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

discord.py中Spy命令return后如何同步停止已注册的on_message等事件

问题根源

你当前的写法存在两个核心问题:

  • @Bot.event装饰器注册的事件是全局绑定到机器人实例的,并不会随着命令函数的return自动销毁,你每次执行Spy命令还会直接覆盖机器人原有的同名全局监听器,会导致其他依赖全局事件的功能失效。
  • 你用全局变量End的逻辑不符合异步代码执行逻辑:注册完事件后判断End的代码会立刻执行,根本等不到用户发送Stop spying!的触发信号。
解决方案

使用discord.py提供的add_listener、remove_listener方法手动管理临时监听器的生命周期,搭配异步事件asyncio.Event等待结束触发信号,保证退出命令时同步销毁监听器。

修复后代码示例

import asyncio
from discord import Member

# 你的Bot初始化代码保持不变

@Bot.command()
async def Spy(ctx, user: Member):
    author = ctx.message.author
    # 用局部异步事件代替全局变量,避免全局污染,适配异步逻辑
    end_event = asyncio.Event()

    # 先定义监听器函数,暂不注册
    async def on_typing(channel, typing_user, when):
        # 此处保留你原有的on_typing逻辑
        ...

    async def on_message(mess):
        if mess.author == author and mess.content == "Stop spying!":
            end_event.set()
        # 如果你没有全局的on_message监听器,才需要加下一行代码,否则可以省略
        # await Bot.process_commands(mess)
    
    # 手动注册临时监听器
    Bot.add_listener(on_typing, 'on_typing')
    Bot.add_listener(on_message, 'on_message')

    try:
        # 等待结束信号,最多等待300秒(可自行修改时长),避免监听器永久残留
        await asyncio.wait_for(end_event.wait(), timeout=300)
    except asyncio.TimeoutError:
        await ctx.send("监听超时,已自动结束")
    finally:
        # 无论触发结束、超时还是出现异常,都强制移除监听器,避免残留
        Bot.remove_listener(on_typing, 'on_typing')
        Bot.remove_listener(on_message, 'on_message')
        await ctx.send("已停止监听")

注意事项

  • 不要在命令内部使用@Bot.event注册事件,该操作会覆盖机器人全局的同名监听器,影响其他功能运行
  • add_listener和remove_listener必须成对使用,第二个参数需要和监听的事件名称完全匹配
  • finally块的移除逻辑必不可少,能避免异常场景下出现监听器残留的问题

内容的提问来源于stack exchange,提问作者FLAK-ZOSO

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 09:30:02