我在看this answer,他们解释了如何用__await__
方法异步初始化一个类。问题是:是否可以在等待类的初始化时传递参数,就像同步初始化时一样?
换句话说,我希望能够做my_class = await MyClass(my_parameter)
,但是我无法以任何方式使它工作。
我应该回到使用__init__
中的经典this answer吗?
你应该只使用__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__
),就像链接到您要执行的建议的帖子一样。
换句话说,我希望能够做
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__
实际上是微不足道的,但您希望返回的实例是可以等待的,则不需要增加拆分初始化的复杂性。
注意:尽管是recommended,asyncio.run()
仍然是临时的。在上面的例子中,它可以很容易地用run_until_complete
替换。