Python - 在某些 class 的非异步 __init__ 中等待异步任务

Python - waiting for asyncio task in non-async __init__ of certain class

我正在制作一个 python class,其中包含一个 __init__ 函数和另一个函数,比方说 f__init__ 函数不是异步的,但另一个函数是。现在,我正在尝试从 __init__.

执行另一个函数

我调查过的事情:

请注意,这是在 Azure Function App 上下文中。

一些示例代码:

import asyncio
class myClass(object):
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2
        #asyncio.create_task(self.f('abc'))
        self.loop = asyncio.get_event_loop()
        self.loop.run_until_complete(self.f('abc'))
    
    async def f(self, x):
        await asyncio.sleep(1)
        self.x = x
        
if __name__ == '__main__':
    cl = myClass(1,2)
    print(cl.x)

这在这个简单的上下文中工作得很好,但在更复杂的上下文中就不行了,比如在 Azure Functions 中,我试图在一个函数中使用 myClass,然后想使用它的“x”属性 .

__init__ 中的代码不能使用 await 所以你需要做两件事中的一件。

__init__ 中启动一些异步任务并提供第二种等待它们的方法:

import asyncio
class myClass(object):
    """ must await on obj.finish_init() before the object can be used """
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2
        self._finish_init_promise = asyncio.create_task(self.f('abc'))
        #self.loop = asyncio.get_event_loop()
        #self.loop.run_until_complete(self.f('abc'))
    async def finish_init(self):
        await self._finish_init_promise
        return self
    
    async def f(self, x):
        await asyncio.sleep(1)
        self.x = x
async def main():
    cl = await myClass(1,2).finish_init()
    print(cl.x)
if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())

然而,构建一个不完整的对象可能是不可取的(您可能希望有一个布尔值来指示它是否准备就绪),因此另一种方法是提供异步 classmethod 来准备数据然后将该数据传递给构造函数:

import asyncio
class myClass(object):
    def __init__(self, arg1, arg2, x):
        self.arg1 = arg1
        self.arg2 = arg2
        self.x = x
    @classmethod
    async def make(cls, arg1, arg2):
        x = await cls.obvious_example_will_be_replaced_with_real_use_case('abc')
        return cls(arg1, arg2, x)
    @staticmethod
    async def obvious_example_will_be_replaced_with_real_use_case(x):
        await asyncio.sleep(1)
        return x
async def main():
    cl = await myClass.make(1,2)
    print(cl.x)
if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())