Create Awaitable Constructors with AsyncMixin
Tags: async, fastapi, python, oops
Published: 2023-07-25 08:06:13

---
title: Create Awaitable Constructors with AsyncMixin
published: true
description: 
tags: async, fastapi, python, oops
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-06-05 12:57 +0000
---
In this blog post, we'll explore how to create an asynchronous constructor in Python using a mixin called `AsyncMixin`. This mixin allows you to use an asynchronous `__ainit__` method that can await other asynchronous methods during initialization. The `__initobj` method acts as a crutch to enable proper `await` behavior when creating instances of the class. I have taken reference from [this] (https://stackoverflow.com/a/68220938) Slack Overflow answer.

### Introduction

In Python, constructors are special methods used to initialize objects when they are created. The traditional constructor, `__init__`, is synchronous, meaning it cannot await asynchronous tasks. However, there are situations where we may want to perform asynchronous operations during object initialization.

The `AsyncMixin` class provides an elegant solution to this problem. It introduces an async constructor, `__ainit__`, which you can use to perform asynchronous operations during object creation. The mixin overrides the `__await__` method, allowing proper `await` behavior when instantiating objects.

### Implementation

Below is the code for the `AsyncMixin` class:

```python
class AsyncMixin:
    def __init__(self, *args, **kwargs):
        """
        Standard constructor used for arguments pass
        Do not override. Use __ainit__ instead
        """
        self.__storedargs = args, kwargs
        self.async_initialized = False

    async def __ainit__(self, *args, **kwargs):
        """Async constructor, you should implement this"""

    async def __initobj(self):
        """Crutch used for __await__ after spawning"""
        assert not self.async_initialized
        self.async_initialized = True
        # pass the parameters to __ainit__ that passed to __init__
        await self.__ainit__(*self.__storedargs[0], **self.__storedargs[1])
        return self

    def __await__(self):
        return self.__initobj().__await__()
```

### How to Use the `AsyncMixin`

To use the `AsyncMixin`, follow these steps:

1. Inherit from `AsyncMixin` when defining your class.
2. Implement the async constructor, `__ainit__`, within your class. This method will contain the asynchronous logic you need during object initialization.
3. When calling the constructor, use `await` to create the object asynchronously.

Here's an example of how you can use the `AsyncMixin`:

```python
class AsyncExample(AsyncMixin):
    async def __ainit__(self, param1, param2):
        # Perform asynchronous operations here
        await self.async_operation1(param1)
        await self.async_operation2(param2)

    async def async_operation1(self, param):
        # Simulate an asynchronous operation
        await asyncio.sleep(1)
        print(f"Async operation 1 with param: {param}")

    async def async_operation2(self, param):
        # Simulate another asynchronous operation
        await asyncio.sleep(2)
        print(f"Async operation 2 with param: {param}")

# Asynchronously create an instance of AsyncExample
async def main():
    obj = await AsyncExample("Parameter 1", "Parameter 2")

# Run the event loop to execute the main coroutine
if __name__ == "__main__":
    import asyncio

    asyncio.run(main())

```

In this example, we've created a class `AsyncExample` that inherits from `AsyncMixin`. The `__ainit__` method performs two asynchronous operations (`async_operation1` and `async_operation2`) using `await`. When creating an instance of `AsyncExample`, we use the `await` keyword to asynchronously construct the object and execute the `__ainit__` method.

### Conclusion

By utilizing the `AsyncMixin`, you can create asynchronous constructors and await asynchronous methods during object initialization. This pattern is particularly useful when dealing with asynchronous operations in Python, allowing you to write cleaner and more efficient code.