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

时间:2018-09-16 22:29:40

标签: python python-3.x async-await python-asyncio

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

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

我应该像在this answer中那样使用经典的__init__吗?

2 个答案:

答案 0 :(得分: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定义)也是如此。当您调用它们时,它们也会创建一个新的协程对象,而您不必立即等待它们。您可以在其他时间对结果使用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__),就像您链接到建议的帖子一样。

答案 1 :(得分: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__实际上微不足道,但是您希望返回的实例可以等待,则不需要拆分初始化的额外复杂性。

注意:尽管asyncio.run()recommended,但仍被标记为临时。在上面的示例中,可以轻松地将其替换为run_until_complete