Issue
I was looking at this answer where they explain how to initialize a class asynchronously with the method __await__
. The question is: is it possible to pass parameters when awaiting the initialization of the class, just like when it is initialized synchronously?
In other words, I'd like to be able to do
my_class = await MyClass(my_parameter)
, however I wasn't able to make it work in any way.
Should I just fall back to using the classic __init__
like in this answer?
Solution
You should just use __init__
. You are creating a regular class instance first, and then await on the instance. These are two separate actions.
For example, you could first create the instance, and then later, separately, await on it:
my_class = MyClass(my_parameter)
result_from_coroutine = await my_class
or you could create a task from it and have the event loop execute it with
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()
The __await__
method is what await
or the event loop use to drive coroutines. The same separation applies to coroutine functions (defined with async def
); they too create a new coroutine object when you call them, and you don't have to await on them immediately. You can use await
on the result at another time.
If you are looking for asynchronous instance creation, then you could hack that up by making the __new__
method into a coroutine:
>>> class Async:
... async def __new__(cls):
... instance = super().__new__(cls)
... return instance
...
>>> Async()
<coroutine object Async.__new__ at 0x103654148>
Awaiting on the coroutine would create the actual instance and return it.
Take into account that this does mean that the __init__
method will be skipped; the latter is only called when the __new__
method directly returns an instance of the class (or a subclass), and a coroutine is not such an instance. You'd have to explicitly do so yourself:
class Async:
async def __new__(cls, *args, **kwargs):
instance = super().__new__(cls)
instance.__init__(*args, **kwargs)
return instance
at which point you could decide to make the __init__
method a coroutine too.
Note that this is really going against the grain. I'd postpone calling dependent coroutines to a later point instead.
For example, you can just store the parameters to the class on the instance and use those when the instance is awaited on (by having __await__
called), exactly as the post you link to advices you to do.
Answered By - Martijn Pieters
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.