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

discord.py中on_message事件如何调用@client.command()定义的命令

discord.py on_message事件中调用已定义warn命令的实现方法

直接裸调用装饰器注册的命令无法生效,核心原因是@client.command()包装的命令依赖Context上下文对象运行,而on_message事件返回的message对象本身就可以用来构造所需上下文,有两种成熟实现方案:

方案1:构造上下文直接调用原命令(无需改动原有warn命令代码)

注意:原代码中@commands.has_permissions(manage_messages=True)放在on_message事件上完全无效,该装饰器仅对注册的命令生效,事件函数不会触发其权限校验逻辑。另外必须先过滤机器人自身发送的消息,避免触发死循环。

修正后的on_message代码如下:

@client.event
async def on_message(message):
    # 跳过机器人发送的消息,防止死循环
    if message.author.bot:
        return

    # 敏感词检测逻辑
    is_violation = False
    violation_reason = "发送包含敏感词的违规内容"
    for word in fwords:
        if word in message.content.lower():
            is_violation = True
            break

    if is_violation:
        print("WARNING: Filtered word")
        # 从message对象构造命令所需的ctx上下文
        ctx = await client.get_context(message)
        # 获取warn命令对象,按参数要求传入ctx、被警告用户、警告原因
        warn_cmd = client.get_command("warn")
        await warn_cmd(ctx, member=message.author, reason=violation_reason)

    # 必须保留这行,否则其他正常注册的命令不会被响应
    await client.process_commands(message)

方案2:抽离公共逻辑(更推荐,维护成本更低)

自动触发警告和手动执行warn命令的核心逻辑完全一致,可以把加警告分、发通知的逻辑抽成独立公共函数,避免绕上下文调用命令,后续修改逻辑也只需要改一处:

  1. 先抽离公共逻辑,调整原有warn命令:
# 公共警告逻辑,所有触发警告的场景都调用这个函数
async def send_warn(channel, warned_member: discord.Member, reason=None):
    add_warning_points(warned_member)
    await channel.send(f'Warned {warned_member.mention} for {reason}')

# 手动触发的warn命令,权限装饰器放在这里才会生效
@client.command()
@commands.has_permissions(manage_messages=True)
async def warn(ctx, member: discord.Member, *, reason=None):
    await send_warn(ctx.channel, member, reason)
  1. 在on_message中直接调用公共函数即可,不需要构造上下文:
@client.event
async def on_message(message):
    if message.author.bot:
        return

    for word in fwords:
        if word in message.content.lower():
            print("WARNING: Filtered word")
            # 直接传入消息频道、违规用户、原因即可触发警告
            await send_warn(message.channel, message.author, reason="发送包含敏感词的违规内容")
            break

    await client.process_commands(message)

两种方案都可以正常实现需求,方案2没有命令调用的额外开销,也不会出现上下文、装饰器校验相关的意外问题,是生产环境更常用的写法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:15:44