在异步初始化时将参数传递给python类

问题描述 投票:1回答:2

我在看this answer,他们解释了如何用__await__方法异步初始化一个类。问题是:是否可以在等待类的初始化时传递参数,就像同步初始化时一样?

换句话说,我希望能够做my_class = await MyClass(my_parameter),但是我无法以任何方式使它工作。

我应该回到使用__init__中的经典this answer吗?

python python-3.x async-await python-asyncio
2个回答
2
投票

你应该只使用__init__。您首先创建一个常规类实例,然后等待实例。这是两个单独的行动。

例如,您可以先创建实例,然后再单独创建实例,等待它:

my_class = MyClass(my_parameter)
result_from_coroutine = await my_class

或者您可以从中创建任务并让事件循环执行它

my_class = MyClass(my_parameter)
task = asyncio.create_task(my_class)  # the loop will await the task
# ...
if task.done():
    result_from_coroutine = task.result()

__await__方法是await或事件循环用来驱动协同程序。同样的分离适用于协程函数(用async def定义);当你调用它们时,它们也会创建一个新的coroutine对象,而你不必立即等待它们。您可以在其他时间对结果使用await

如果您正在寻找异步实例创建,那么您可以通过将__new__ method变成协程来破解它:

>>> class Async:
...     async def __new__(cls):
...         instance = super().__new__(cls)
...         return instance
...
>>> Async()
<coroutine object Async.__new__ at 0x103654148>

等待协程会创建实际的实例并将其返回。

考虑到这意味着将跳过__init__方法;后者仅在__new__方法直接返回类(或子类)的实例时调用,并且协程不是这样的实例。你必须自己明确这样做:

class Async:
    async def __new__(cls, *args, **kwargs):
        instance = super().__new__(cls)
        instance.__init__(*args, **kwarg)
        return instance

此时你可以决定使__init__方法成为一个协程。

请注意,这实际上是违背粮食的。我会推迟调用依赖协程到以后的位置。

例如,您可以将参数存储在实例上的类中,并在等待实例时使用这些参数(通过调用__await__),就像链接到您要执行的建议的帖子一样。


0
投票

换句话说,我希望能够做my_class = await MyClass(my_parameter),但是我无法以任何方式使它工作。

您可以通过实施MyClass使__await__等待:

class MyClass:
    def __init__(self, delay):
        self.delay = delay

    async def __await__(self):
        await asyncio.sleep(self.delay)

asyncio.run(MyClass(2)) # sleeps 2 seconds

链接答案中的代码做了类似的事情,但它更复杂,因为它假设__init__本身需要await。如果情况并非如此,并且您的__init__实际上是微不足道的,但您希望返回的实例是可以等待的,则不需要增加拆分初始化的复杂性。

注意:尽管是recommendedasyncio.run()仍然是临时的。在上面的例子中,它可以很容易地用run_until_complete替换。

© www.soinside.com 2019 - 2024. All rights reserved.