1. ホーム
  2. python

[解決済み] init__でawaitを使ってクラス属性を設定する方法

2022-05-11 10:10:19

質問

どのようにすれば、クラスを await をコンストラクタやクラス本体に記述することはできますか?

例えば私が欲しいもの。

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'

またはclass body属性の例です。

class Foo(object):

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

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

foo = Foo(settings)

私の解決策 (しかし、私はよりエレガントな方法を見たいと思います)

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()

どのように解決するのですか?

ほとんどのマジックメソッドは async def / await - を使用する必要があります。 await を使うのは、専用の非同期マジックメソッドである __aiter__ , __anext__ , __aenter__ そして __aexit__ . 他のマジックメソッドの内部で使用すると、次のようにまったく動作しません。 __init__ (のように全く動作しないか(ここの他の回答で説明されているようなトリックを使用しない限り)、非同期コンテキストでマジックメソッドの呼び出しをトリガーするものを常に使用することを強制されます。

既存の asyncio ライブラリは、2つの方法のうちの1つでこれを扱う傾向があります。まず、ファクトリーパターンが使われているのを見たことがあります ( asyncio-redis など)。

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)

他のライブラリは、ファクトリーメソッドではなく、オブジェクトを作成するトップレベルのコルーチン関数を使用します。

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)

create_pool 関数から aiopg で呼び出したい __init__ は、実はこのパターンを正確に使っているのです。

これは少なくとも __init__ の問題を解決します。私が思い出せる限り、非同期呼び出しを行うクラス変数を見たことがないので、確立されたパターンが出現しているのかどうかはわかりません。