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

如何在discord.py中实现通过ID或提及警告成员?

问题

Discord机器人的warn命令目前仅支持通过@提及成员发起警告,希望扩展为支持用户ID或**@提及成员**两种方式触发警告操作,但尝试设置两个变量时会出现参数分配错误(比如输入ID时被分配给接收提及的变量)。

解决方案

Discord.py的discord.Member类型注解本身就支持自动解析@提及和用户ID,无需额外设置两个变量。同时优化警告记录的存储逻辑(用用户ID代替用户名,避免重名冲突),修复过时API和拼写错误。以下是修改后的完整代码:

import json
import discord
from discord.ext import commands

with open('reports.json', encoding='utf-8') as f:
    try:
        report = json.load(f)
    except ValueError:
        report = {}
        report['users'] = []

@client.command(pass_context=True)
@commands.has_permissions(kick_members=True)
async def warn(ctx, member: discord.Member, *reason: str):
    guild = ctx.guild
    requester = ctx.message.author

    # 简化角色位置获取,无需重复调用get_member
    requester_top_role_pos = requester.top_role.position
    member_top_role_pos = member.top_role.position

    if requester_top_role_pos > member_top_role_pos:
        if not reason:
            await ctx.send("Please provide a reason")
            return
        reason = ' '.join(reason)
        
        # 改用用户ID作为唯一标识,避免重名问题
        user_found = False
        for current_user in report['users']:
            if current_user['id'] == str(member.id):
                current_user['reasons'].append(reason)
                user_found = True
                break
        if not user_found:
            report['users'].append({
                'id': str(member.id),
                'name': member.name,
                'reasons': [reason,]
            })
        
        with open('reports.json','w+', encoding='utf-8') as f:
            json.dump(report, f, indent=2)
            await ctx.send(f"<:classic_check_mark:1055182126103937155> {member.mention} has been warned!")
            try:
                await member.send(f"<:warning_icon:1055184901919494195> You have been warned from {guild.name}\n\n<:warning_icon:1055184901919494195> Reason: {reason}")
            except discord.Forbidden:
                await ctx.send(f"无法给{member.mention}发送私信,对方可能关闭了私信功能")
        
    elif requester_top_role_pos < member_top_role_pos:
        await ctx.send(f"<:failed:1055182259054985306> {member.mention} 的角色等级比你高,无法警告该成员!")

@warn.error
async def warn_error(ctx, error):
    if isinstance(error, commands.MissingPermissions):
        await ctx.send("<:failed:1055182259054985306> 你没有使用该命令的权限。")
    elif isinstance(error, commands.MissingRequiredArgument):
        await ctx.send("<:syntax:1055182220140232704> 参数错误 | --warn <@成员/用户ID> <警告理由>")
    elif isinstance(error, commands.MemberNotFound):
        await ctx.send("<:failed:1055182259054985306> 找不到该成员,请检查用户ID或提及是否正确。")

@client.command(pass_context=True)
@commands.has_permissions(kick_members=True)
async def warnings(ctx, member: discord.Member):
    # 同样改用用户ID查询
    for current_user in report['users']:
        if current_user['id'] == str(member.id):
            await ctx.send(f"{member.name} 共有 {len(current_user['reasons'])} 条警告记录:{','.join(current_user['reasons'])}")
            break
    else:
        await ctx.send(f"{member.name} 没有警告记录")
关键修改说明
  • 支持双方式解析:将参数类型从discord.User改为discord.Member,该类型会自动识别并解析@提及和用户ID,无需额外处理参数分配问题。
  • 修复过时API:替换已弃用的client.say为ctx.send。
  • 避免重名冲突:改用用户ID作为警告记录的唯一标识,彻底解决用户名重复导致的记录混乱问题。
  • 增强错误处理:新增MemberNotFound错误捕获,当用户输入的ID无效时给出明确提示;同时增加私信发送失败的异常处理。
  • 简化代码逻辑:移除不必要的get_member调用,ctx.author本身就是discord.Member实例,可直接获取角色信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 01:05:20