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?
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()
__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, **kwarg) 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.