Discord投票机器人on_reaction_add事件访问async函数变量报错如何解决
问题原因
- 你代码里的
new_poll是被@bot.command装饰器包装后的Discord命令对象,而非普通函数,你在new_poll函数内部定义的tv_embed、message都属于函数运行时的局部变量,函数执行完毕后就会被回收,本身也不属于Command对象的属性,所以直接访问new_poll.tv_embed必然会触发AttributeError。 - 除此之外你原来的
new_poll里计算总票数的逻辑只会在创建投票时执行一次,本身就没有和后续的用户反应事件做联动。
修复方案
- 首先定义一个全局缓存字典,用来存储所有有效投票消息的关联数据:
# 全局缓存,key为投票消息的id,value存储对应需要的参数 poll_cache = {}
- 修改
new_poll命令,创建投票后把消息ID和对应参数存入缓存:
@bot.command(name="newpoll") async def new_poll(ctx, question, *options): if len(options) > 12: await ctx.send("You can have a maximum of 12 choices in your poll") else: embed = discord.Embed(title = "Poll", description = question, colour = discord.Colour.red()) fields = [("Options", "\n".join([f"{emotes[idx]} {option}" for idx, option in enumerate(options)]), False), ("Instructions", "Please react in order to vote!", False)] for name, value, inline in fields: embed.add_field(name = name, value = value, inline = inline) embed.add_field(name = "Total votes", value = 0, inline = False) message = await ctx.send(embed = embed) for emoji in emotes[:len(options)]: await message.add_reaction(emoji) # 把投票消息id和选项数量存入缓存,方便后续事件里调用 poll_cache[message.id] = { "option_count": len(options) }
- 修改
on_reaction_add事件,先判断是否是投票消息,再更新票数:
@bot.event async def on_reaction_add(reaction, user): # 忽略机器人自己的反应 if user.bot: return # 检查触发反应的消息是不是已创建的投票消息 if reaction.message.id not in poll_cache: return # 获取当前投票的选项数量 option_count = poll_cache[reaction.message.id]["option_count"] # 计算总票数:所有反应数之和减去机器人自己加的初始反应数 total_votes = sum(r.count for r in reaction.message.reactions) - option_count # 更新embed的总票数字段 new_embed = reaction.message.embeds[0] new_embed.set_field_at(2, name="Total votes", value=total_votes, inline=False) await reaction.message.edit(embed=new_embed)
补充说明
- 如果机器人重启,缓存里的投票数据会丢失,如果你需要持久化支持,可以把缓存数据存在数据库或者本地文件里。
- 建议同步处理
on_reaction_remove事件,用户取消投票时也同步更新总票数。
内容的提问来源于stack exchange,提问作者iktefish
相关产品推荐
相关产品推荐

