【问题标题】:How to add a function to discord.py event loop?如何向 discord.py 事件循环添加函数?
【发布时间】:2019-01-12 07:56:01
【问题描述】:

我正在使用带有discord.py 的Python。文档 here

我有一个在 Discord 服务器上运行的机器人,它将服务器与 subreddit 链接。用户有各种命令来执行诸如获取最热门提交、获取最新提交等操作。

我想为机器人添加一些功能,其中之一是关键字通知器。机器人应该在 subreddit 中搜索标题中的关键字,然后通知用户他们是否在该关键字的列表中。我知道如何做到这一点,我已经做过很多次了,但我不知道如何使用 Discord 机器人来做到这一点。我没有使用 asynchio 或任何类型的异步编程的经验。

我尝试这样做的方式有效,但它非常笨拙而且绝对不好。在 on message() 函数的顶部,我只是添加了对 search_submissions() 函数的调用,这样每当有人在服务器上发送新消息时,机器人就会扫描 Reddit 提交的内容。服务器很忙,这可以相对较好地工作,但我真的想以“正确”的方式来做。

我不知道如何调用search_submissions() 函数而不将它放在on_message() 中。


编辑额外代码:

import discord

TOKEN = "redacted"
client = discord.Client()

@client.event
async def reddit_search():
    print("Searching")

@client.event
async def on_message(message):
    if message.content.startswith("reddit!hot"):
        # Get hot
    # Do other things.

@client.event
async def on_ready():
    print("Connected to Discord as {}.".format(client.user.name))

client.run(TOKEN)

【问题讨论】:

  • 澄清一下:您希望search_submissions() 持续运行还是仅在用户发送消息时运行?

标签: python bots discord


【解决方案1】:

您可以使用Client.loop.create_task(search_submissions()) 向机器人事件循环添加一个函数,如下所示:

async def search_submissions():
    pass

client = discord.Client()

client.loop.create_task(search_submissions())
client.run(TOKEN)


更新:

如果你想让你的函数继续工作,你可以把它放在一个while循环中,中间有一些睡眠:

async def search_submissions():
    while(true):
        # do your stuff
        await asyncio.sleep(1)

【讨论】:

  • 什么是bot?我的代码中没有这个。我编辑了原始问题中的代码,但删除了每个函数中的所有内容以节省空间。一切都在那里,只是缺少 print 和 if 语句。
  • @JohnYuki 对不起,我修正了我的答案,我只是习惯使用commands 模块。
  • 没问题。所以我添加了create_task 行,但它并没有超过它。当我启动机器人时,它会通过该功能一次,但就是这样。
  • @JohnYuki 更新了我的答案。
  • search_submissions() 如何与机器人的其余部分交流其结果?
【解决方案2】:

您希望您的 search_submissions() 函数为 异步,以便您的机器人的其他功能仍然可以被调用并且您的机器人保持响应。将其定义为def async 并使用aiohttp 向reddit 发送异步HTTP 请求——它的作用是发送请求,将控制权交给事件循环,然后在结果传回后收回控制权。如果您在此处使用标准 HTTP 库,那么您的整个机器人将被阻止,直到结果返回。当然,这只有在任务主要受 I/O 限制且较少受 CPU 限制时才有意义。

然后在on_message(message) 中调用search_submissions() -- 但使用result = await search_submissions() 异步调用它。一旦search_submissions 的结果准备好,这将恢复on_message 的执行。

如果您真的想在等待search_submissions(我认为不太可能)的同时在相同的上下文中做其他事情,请将其发送为task = asyncio.create_task(search_submissions())。这将立即启动任务并允许您在同一函数中执行其他操作。一旦你需要结果,你必须result = await task

async def search_submissions():
    async with aiohttp.ClientSession() as session:
        async with session.get(some_reddit_url) as response:
            return await response.read()

@client.event
async def on_message(message):
    if message.content.startswith("reddit!hot"):
        result = await search_submissions()
        await message.channel.send(result)

【讨论】:

    【解决方案3】:

    这里的其他答案没有考虑 discord.py 的有用 tasks.loop 装饰器。

    要使事件每 5 秒发生一次,您可以使用

    from discord.ext import tasks, commands
    
    class MyCog(commands.Cog):
        def __init__(self):
            self.foo.start()
    
        def cog_unload(self):
            self.printer.cancel()
    
        @tasks.loop(seconds=5.0)
        async def foo(self):
            print('bar')
    

    更多信息可以在这里找到:https://discordpy.readthedocs.io/en/latest/ext/tasks/

    【讨论】:

      猜你喜欢
      • 2019-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多