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

Posted

技术标签:

【中文标题】在 Python __init__ 方法中使用异步等待【英文标题】:Using async await in Python __init__ method 【发布时间】:2019-09-05 20:11:18 【问题描述】:

我正在编写一个类,并想在__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__ 必须是同步的,所以我在init 调用期间将firstRun 设置为True,然后我可以稍后用它来告诉代码之前是否运行过

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

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

【问题讨论】:

我认为你应该有一个函数来执行异步任务,然后同步初始化并返回类的实例。 【参考方案1】:

有点别扭,不过你可以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__ 设置了

【讨论】:

这似乎可以解决我的问题。为什么将coro 变成Task?是否只是为了能够获得返回值?如果我不需要返回值,我可以只做run_until_complete(coro)吗? 我认为,如果您这样做,它只会在后台为该协程创建一个任务或未来,因此不应该对性能产生任何影响。

以上是关于在 Python __init__ 方法中使用异步等待的主要内容,如果未能解决你的问题,请参考以下文章

Python 中的异步 PureMVC

python中super().__init__和类名.__init__的区别

Python中__new__()方法的使用和实例化

python面向对象中的__init__方法怎么理解?

Python之__init__函数及__init__.py

python中的__init__方法