Discord.py 如何实现消息反应等待判定及解决相关报错、功能异常
问题原因
首次报错原因
self.bot.wait_for('reaction_add') 的原生返回值是包含两个元素的元组:依次为触发事件的Reaction对象、触发反应的User对象。原代码仅用单个变量接收返回值,将整个元组赋值给reaction变量,不存在.emoji属性,因此抛出AttributeError: 'tuple' object has no attribute 'emoji'错误。
修改后功能失效原因
完成元组解包后,功能仅能识别1️⃣反应、其余逻辑不触发,核心问题有两个:
- 未设置事件过滤条件:代码执行
add_reaction添加三个表情时,每添加一个表情都会触发一次reaction_add事件。第一个被触发的是添加1️⃣的事件,此时触发用户为bot自身,代码执行if user == self.bot.user: return直接跳出整个监听流程,根本无法捕获后续添加2️⃣、3️⃣的事件,更等不到用户的反应操作。 - 未限定监听范围:未指定仅监听
embedX这条消息的反应、未指定仅匹配指令发起用户的操作,容易捕获无关消息、无关用户的反应事件,打断正常流程。
修复实现
调整逻辑
- 自定义事件检查函数,仅同时满足三个条件的事件才会被
wait_for捕获:- 反应触发的消息为之前发送的
embedX - 触发反应的用户为当前指令的发起者
ctx.author,排除bot与其他无关用户的操作 - 反应表情为预设的三个可选表情,避免其他无关表情打断流程
- 反应触发的消息为之前发送的
- 将检查函数作为参数传入
wait_for,无需在回调逻辑中提前终止流程
参考代码
e = discord.Embed(color=discord.Color.gold()) e.title = "Woah, look!" e.description = "**Does this work?**" e.add_field(name="1️⃣", value="Yes", inline=False) e.add_field(name="2️⃣", value="No", inline=False) e.add_field(name="3️⃣", value="Maybe", inline=False) e.set_footer(text="You have 10 seconds to answer the question", icon_url=self.bot.user.avatar_url) e.timestamp = datetime.datetime.utcnow() embedX = await ctx.send(embed=e) await embedX.add_reaction("1️⃣") await embedX.add_reaction("2️⃣") await embedX.add_reaction("3️⃣") # 定义有效反应匹配规则 def reaction_check(reaction, user): is_target_msg = reaction.message.id == embedX.id is_target_user = user.id == ctx.author.id is_valid_emoji = str(reaction.emoji) in ("1️⃣", "2️⃣", "3️⃣") return is_target_msg and is_target_user and is_valid_emoji try: reaction, user = await self.bot.wait_for( "reaction_add", timeout=10, check=reaction_check ) if str(reaction.emoji) == "1️⃣": await embedX.edit(embed=er) else: await ctx.send(embed=ew) except asyncio.TimeoutError: await embedX.edit(embed=etl)
内容的提问来源于stack exchange,提问作者Dominik
相关产品推荐
相关产品推荐

