如何在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
相关产品推荐
相关产品推荐

