我正在看this answer,他们解释了如何使用方法__await__
异步初始化类。问题是:是否可以在等待类初始化时传递参数,就像同步初始化时一样?
换句话说,我希望能够
my_class = await MyClass(my_parameter)
,但是我无法使其以任何方式工作。
我应该像在this answer中那样使用经典的__init__
吗?
答案 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
。