How to set class attribute with await in init

How can I define a class with await in the constructor or class body?

For example what I want:

    import asyncio

    # some code


    class Foo(object):

        async def __init__(self, settings):
            self.settings = settings
            self.pool = await create_pool(dsn)

    foo = Foo(settings)
    # it raises:
    # TypeError: __init__() should return None, not 'coroutine'

or example with class body attribute:

    class Foo(object):

        self.pool = await create_pool(dsn)  # Sure it raises syntax Error

        def __init__(self, settings):
            self.settings = settings

    foo = Foo(settings)

My solution (But I would like to see a more elegant way)

    class Foo(object):

        def __init__(self, settings):
            self.settings = settings

        async def init(self):
            self.pool = await create_pool(dsn)

    foo = Foo(settings)
    await foo.init()

Most magic methods aren't designed to work with async def/await - in general, you should only be using await inside the dedicated asynchronous magic methods - __aiter__, __anext__, __aenter__, and __aexit__. Using it inside other magic methods either won't work at all (as is the case with __init__), or will force you to always use whatever triggers the magic method call in an asynchronous context.

Existing asyncio libraries tend to deal with this in one of two ways: First, I've seen the factory pattern used (asyncio-redis, for example):

    import asyncio

    dsn = "..."

    class Foo(object):
        @classmethod
        async def create(cls, settings):
            self = Foo()
            self.settings = settings
            self.pool = await create_pool(dsn)
            return self

    async def main(settings):
        settings = "..."
        foo = await Foo.create(settings)

Other libraries use a top-level coroutine function that creates the object, rather than a factory method:

    import asyncio

    dsn = "..."

    async def create_foo(settings):
        foo = Foo(settings)
        await foo._init()
        return foo

    class Foo(object):
        def __init__(self, settings):
            self.settings = settings

        async def _init(self):
            self.pool = await create_pool(dsn)

    async def main():
        settings = "..."
        foo = await create_foo(settings)

The create_pool function from aiopg that you want to call in __init__ is actually using this exact pattern.

This at least addresses the __init__ issue. I haven't seen class variables that make asynchronous calls in the wild that I can recall, so I don't know that any well-established patterns have emerged.

From: stackoverflow.com/q/33128325