在Python __init__方法中使用异步等待

时间:2019-04-15 19:28:02

标签: python async-await discord.py

我正在编写一个类,并想在__init__方法中使用异步函数来设置该类所需的一些变量。问题是,我不能这样做,因为__init__必须是同步的。

这是我的代码的相关部分(为简单起见,其逻辑保持不变):

# This has to be called outside of the class
asyncDatabaseConnection = startDBConnection()

class discordBot(discord.Client):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Init is only run once, but we cant use async stuff here
        self.firstRun = True

    async def on_ready(self):
        # Other stuff happens here but it doesen't involve this question

        # on_ready is called when bot is ready, but can be called multiple times when running
        # (if bot has to reconnect to API), so we have to check
        if self.firstRun:
            await asyncDatabaseConnection.setValue("key", "value")
            self.firstRun = False

if __name__ == "__main__":
    # Instance class and start async stuff
    bot = discordBot()
    bot.run()

正如您所看到的,它是针对Discord机器人的,但这并不重要,它更多地是关于逻辑。

我要调用的函数是asyncDatabaseConnection.setValue("key", "value")

就像我说的那样,我无法从__init__调用它,因为__init__必须是同步的,所以我在初始化调用期间将firstRun设置为True,然后我以后可以用它来告诉代码是否已经运行过

on_ready是在机器人准备开始发送/接收数据时调用的函数,因此我可以将其用作第二个__init__。问题来自这样一个事实:在程序的整个运行过程中,on_ready可以被多次调用,这意味着我必须进行前面所述的firstRun检查。

这似乎是很多代码,它们仅在启动时做1件事(以及在调用on_ready时增加了开销,无论多么小)。有没有更清洁的方法?

1 个答案:

答案 0 :(得分:3)

有点尴尬,但是您可以create a Task,然后运行它并获得结果。如果您经常这样做,可能会有助于编写一个辅助函数:

def run_and_get(coro):
    task = asyncio.create_task(coro)
    asyncio.get_running_loop().run_until_complete(task)
    return task.result()

class discordBot(discord.Client):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        run_and_get(asyncDatabaseConnection.setValue("key", "value"))

这取决于有一个正在运行的事件循环,我相信Client.__init__已建立