Discord.py: 多个多页消息
Discord.py: Multiple multipage messages
编辑:
解决方法是在check函数中添加一个条件,我已经在后续的回答中发布了详细信息。
主要问题:
我是新手 python 并决定通过创建一个 discord 机器人来学习它。
根据用户命令,我能够让机器人发送一条消息,该消息可以根据此设计更改页面:
我可以很好地更改一条消息的页面,但是,如果用户多次调用该命令,对其中一条机器人发送的消息做出反应会更改所有未超时消息的页面。我可以在代码中更改什么,以便对一条消息做出反应不会触发其他消息中的页面更改?
补充问题:
def check(reaction, user):
return user == ctx.author and str(reaction.emoji) in ["◀️", "▶️"]
# This makes sure nobody except the command sender can interact with the "menu"
- 我知道wait_for会使用这个函数作为检查,但是检查参数是在哪里以及如何传入的?如果可能,如何添加更多参数?
reaction, user = await bot.wait_for("reaction_add", timeout=60, check=check)
- 在文档中,我无法确定 wait_for 方法的 return 值,看起来它在不同情况下会发生变化。
- 我们没有将消息实例传递给 wait_for 方法,那么该方法如何知道要等待对哪条消息做出反应?
- 如果检查不通过,程序流程会怎样?似乎仅当 check() return 为真时,该行下的语句才会执行。但是当检查失败时会发生什么?
比您提供的方法更好的替代方法是使用 ext.menus
(它处于测试阶段,因此还没有任何文档,要安装它 python -m pip install -U git+https://github.com/Rapptz/discord-ext-menus
)
例子
from discord.ext import menus
class MyMenu(menus.Menu):
async def send_initial_message(self, ctx, channel):
return await channel.send(f'Hello {ctx.author}')
@menus.button('\N{THUMBS UP SIGN}')
async def on_thumbs_up(self, payload):
await self.message.edit(content=f'Thanks {self.ctx.author}!')
@menus.button('\N{THUMBS DOWN SIGN}')
async def on_thumbs_down(self, payload):
await self.message.edit(content=f"That's not nice {self.ctx.author}...")
@menus.button('\N{BLACK SQUARE FOR STOP}\ufe0f')
async def on_stop(self, payload):
self.stop()
# later
@bot.command()
async def menu_example(ctx):
m = MyMenu()
await m.start(ctx)
很遗憾,我无法回答您的第一个问题,我不确定为什么会这样,抱歉。
回答您的其他问题:
wait_for
采用与事件相同的参数,on_message
采用 message
因此检查将采用 message
作为单个参数(该方法也将仅 return message
)。添加更多参数它与装饰器的基础非常相似,我们将检查包装在另一个外部函数中
def check(func): # The ADDITIONAL arguments we want to pass, in this example another function
def inner_check(reaction, user): # The actual check
return user == ctx.author and func(reaction, user)
return inner_check
# To use it Note how I'm calling the check an additional argument
reaction, user = await bot.wait_for('reaction_add', check=check(lambda r, u: return True), timeout=60.0)
Python decorator basics
- 同第一题
- 机器人等待添加任何反应,如果检查函数 returns
True
它将 return 值
- 如果检查 returns 而不是
True
机器人将等待直到函数 returns True
或超时结束
感谢 Łukasz Kwieciński 回答我的其他问题。因为我了解到 wait_for 等待对任何消息的任何反应,所以我向 check() 函数添加了一个附加条件。现在每条消息都相互独立了。
message = await ctx.send(f"Page {cur_page}/{pages}:\n{contents[cur_page-1]}")
# getting the message object for editing and reacting
def check(reaction, user):
if reaction.message != message:
return false
# SOLUTION: Checks if the message reacted on is the same as the one the bot sent
return user == ctx.author and str(reaction.emoji) in ["◀️", "▶️"]
# This makes sure nobody except the command sender can interact with the "menu"
但是,此修复可能会导致性能问题。对于每条尚未超时的机器人消息,对服务器上的任何消息做出反应都会导致它 运行 check() 多次。
编辑:
解决方法是在check函数中添加一个条件,我已经在后续的回答中发布了详细信息。
主要问题:
我是新手 python 并决定通过创建一个 discord 机器人来学习它。
根据用户命令,我能够让机器人发送一条消息,该消息可以根据此设计更改页面:
我可以很好地更改一条消息的页面,但是,如果用户多次调用该命令,对其中一条机器人发送的消息做出反应会更改所有未超时消息的页面。我可以在代码中更改什么,以便对一条消息做出反应不会触发其他消息中的页面更改?
补充问题:
def check(reaction, user):
return user == ctx.author and str(reaction.emoji) in ["◀️", "▶️"]
# This makes sure nobody except the command sender can interact with the "menu"
- 我知道wait_for会使用这个函数作为检查,但是检查参数是在哪里以及如何传入的?如果可能,如何添加更多参数?
reaction, user = await bot.wait_for("reaction_add", timeout=60, check=check)
- 在文档中,我无法确定 wait_for 方法的 return 值,看起来它在不同情况下会发生变化。
- 我们没有将消息实例传递给 wait_for 方法,那么该方法如何知道要等待对哪条消息做出反应?
- 如果检查不通过,程序流程会怎样?似乎仅当 check() return 为真时,该行下的语句才会执行。但是当检查失败时会发生什么?
比您提供的方法更好的替代方法是使用 ext.menus
(它处于测试阶段,因此还没有任何文档,要安装它 python -m pip install -U git+https://github.com/Rapptz/discord-ext-menus
)
例子
from discord.ext import menus
class MyMenu(menus.Menu):
async def send_initial_message(self, ctx, channel):
return await channel.send(f'Hello {ctx.author}')
@menus.button('\N{THUMBS UP SIGN}')
async def on_thumbs_up(self, payload):
await self.message.edit(content=f'Thanks {self.ctx.author}!')
@menus.button('\N{THUMBS DOWN SIGN}')
async def on_thumbs_down(self, payload):
await self.message.edit(content=f"That's not nice {self.ctx.author}...")
@menus.button('\N{BLACK SQUARE FOR STOP}\ufe0f')
async def on_stop(self, payload):
self.stop()
# later
@bot.command()
async def menu_example(ctx):
m = MyMenu()
await m.start(ctx)
很遗憾,我无法回答您的第一个问题,我不确定为什么会这样,抱歉。
回答您的其他问题:
wait_for
采用与事件相同的参数,on_message
采用message
因此检查将采用message
作为单个参数(该方法也将仅 returnmessage
)。添加更多参数它与装饰器的基础非常相似,我们将检查包装在另一个外部函数中
def check(func): # The ADDITIONAL arguments we want to pass, in this example another function
def inner_check(reaction, user): # The actual check
return user == ctx.author and func(reaction, user)
return inner_check
# To use it Note how I'm calling the check an additional argument
reaction, user = await bot.wait_for('reaction_add', check=check(lambda r, u: return True), timeout=60.0)
Python decorator basics
- 同第一题
- 机器人等待添加任何反应,如果检查函数 returns
True
它将 return 值 - 如果检查 returns 而不是
True
机器人将等待直到函数 returnsTrue
或超时结束
感谢 Łukasz Kwieciński 回答我的其他问题。因为我了解到 wait_for 等待对任何消息的任何反应,所以我向 check() 函数添加了一个附加条件。现在每条消息都相互独立了。
message = await ctx.send(f"Page {cur_page}/{pages}:\n{contents[cur_page-1]}")
# getting the message object for editing and reacting
def check(reaction, user):
if reaction.message != message:
return false
# SOLUTION: Checks if the message reacted on is the same as the one the bot sent
return user == ctx.author and str(reaction.emoji) in ["◀️", "▶️"]
# This makes sure nobody except the command sender can interact with the "menu"
但是,此修复可能会导致性能问题。对于每条尚未超时的机器人消息,对服务器上的任何消息做出反应都会导致它 运行 check() 多次。