【问题标题】:How do I check and wait for a reaction under a message?如何检查并等待消息下的反应?
【发布时间】:2021-04-23 06:24:30
【问题描述】:

我有一个嵌入得到多个反应的事件。在这里,用户有 x 秒的时间来选择反应。如果这是“错误的”,则应该吐出一个错误。如果反应是我定义的所需反应,则应出现另一条消息。我有这个代码,但我无法进一步了解:

        await embedX.add_reaction("1️⃣")
        await embedX.add_reaction("2️⃣")
        await embedX.add_reaction("3️⃣")
        try:
            reaction = await self.bot.wait_for('reaction_add', timeout=10)
            if str(reaction.emoji) == "1️⃣":
                await ctx.send("Congrats, right answer.")
            else:
                await ctx.send("Incorrect reaction.")
        except asyncio.TimeoutError:
            await ctx.send("Took too long.")

错误:

AttributeError: 'tuple' object has no attribute 'emoji'.

我对 Python 还是很陌生,所以我希望在这里找到帮助。

得到帮助后,我的代码现在如下所示:

        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️⃣")
        try:
            reaction, user = await self.bot.wait_for('reaction_add', timeout=10)
            if user == self.bot.user:
                return
            if str(reaction.emoji) == "1️⃣":
                await embedX.edit(embed=er)
            else:
                await ctx.send(embed=ew)
        except asyncio.TimeoutError:
            await embedX.edit(embed=etl)

有时机器人会计算反应,只是1 - 对其他人他没有反应,但他没有做的是:如果反应错误,则放弃/编辑嵌入。 (erew 实际上是我之前定义的其他嵌入。)

【问题讨论】:

    标签: python discord discord.py


    【解决方案1】:

    您的错误消息应该给您一个提示:您收到的是来自self.bot.wait_fortuple,而不是discord.Reaction

    使用Client.wait_for 时,请记住它返回的内容(强调我的):

    不返回任何参数、单个参数或多个参数的元组,以反映事件引用中传递的参数。

    查看on_reaction_add event,我们可以看到该事件的有效负载是一个discord.Reaction 和一个discord.User 对象。使用wait_for(<event>) 时,您将获得与扩展on_<event> 并以这种方式处理相同的有效负载。

    所以把它们放在一起,这一行:

    await self.bot.wait_for('reaction_add', timeout=10)
    

    返回 tupleReactionUser,例如(<Reaction ...>, <User ...>)。所以你只需要稍作修改:

    reaction, user = await self.bot.wait_for('reaction_add', timeout=10)
    

    这里我们使用元组解包(或多重赋值,如果您愿意)从返回的元组中提取所需的值。

    避免反馈循环

    由于您将收到所有事件,包括由您的机器人引起的事件,您需要确保在事件由您的机器人引起时忽略该事件以避免反馈循环。您可以在事件处理程序中使用以下方法轻松防范这种情况:

    # Assuming `self` is an instance of `discord.Client`
    if user == self.user:  # `user` here comes from the event payload
        return
    

    作为您情况的具体示例:

    reaction, user = await self.bot.wait_for('reaction_add', timeout=10)
    if user == self.bot.user:
        return
    

    【讨论】:

    • 感谢完美的解释。但是我的机器人发疯了,因为我没有建立支票。有什么反应可以让机器人不把自己的反应算作答案吗?我想这也是我不工作的原因asyncio.TimeoutError
    • 在大多数情况下,您通常希望忽略由您的机器人引起的事件,以免最终出现反馈循环。您可以通过检查事件是否是由您的机器人引起的很容易地防止这种情况发生:if user == self.user: return。我将更新答案以包含此内容。
    • 你真好,谢谢。否则我会使用有效负载事件来完成它,但我想它可以更快更容易地完成。
    • 任何一种方法都可以,wait_for 在这里是一个完全有效的选择。你接近他们的方式只是略有不同,仅此而已。 :)
    • 我将把它移到聊天中,因为它有点冗长:chat.stackoverflow.com/rooms/227509/…
    猜你喜欢
    • 2020-09-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-23
    • 2020-12-03
    • 2023-03-14
    • 2021-01-31
    • 2021-08-13
    • 2021-06-22
    相关资源
    最近更新 更多