在Python的__init__方法中使用异步等待(async await)

8
我正在编写一个类,并希望在__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,并在init调用期间使用它,然后稍后可以使用它来告诉代码先前是否已运行

on_ready是一个函数,当机器人准备好开始发送/接收数据时调用,因此我可以将其用作第二个__init__。问题在于,on_ready可以在程序运行期间多次调用,这意味着我必须具有我之前描述过的firstRun检查。

这似乎是为了在启动时执行1件事(以及在调用on_ready时添加开销,即使很小)。有没有更简洁的方法来做到这一点?


我认为你应该有一个执行异步任务的函数,然后同步地初始化并返回类的实例。 - Jared Smith
1个回答

14

有点别扭,但你可以创建一个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__会设置它。


这似乎可以解决我的问题。为什么要将 coro 转换为 Task?只是为了能够获得返回值吗?如果我不需要返回值,我可以直接使用 run_until_complete(coro) 吗? - psidex
我认为如果你这样做,它只是在幕后为该协程创建了一个任务或未来对象,因此不应该有任何性能影响。 - Patrick Haugh
2
我收到了“此事件循环已在运行中”的消息。 - Hacker
@黑客,请创建一个 [mre] 并提出你自己的问题。 - Karl Knechtel
注释用于请求澄清或指出帖子中的问题。 - Hacker
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接