Как правильно наследовать метод класса

У меня есть класс подключения к базе данных, который создает пул соединений. Теперь, когда приложение растет и я добавляю различные типы модулей записи базы данных, я хочу переместить соединения с базой данных в отдельный класс и наследовать от него. Пока у меня это:

class ServiceDB:
    @classmethod
    async def init(cls, settings):
        self = ServiceDB()
        self.pool = await asyncpg.create_pool(
            database=settings["POSTGRES_DB"],
            user=settings["POSTGRES_USER"],
            password=settings["POSTGRES_PASSWORD"],
            host=settings["DB_HOST"],
            port=settings["DB_PORT"],
        )
        return self



class ChildWriter(ServiceDB):
    async def write_db(self, query):
        # Write to specific table
        pass



if __name__ == "__main__":
    settings = {'info': "some connection settings"}
    query = "SELECT * FROM 'table'"
    connection = await ChildWriter().init(settings)
    await connection.write_db(msg, query)

Когда я запускаю это, я получаю AttributeError: 'ServiceDB' object has no attribute 'write_db'. Как правильно расширить ServiceDB с помощью метода write_db?


person G.M    schedule 23.07.2020    source источник


Ответы (1)


Классовые методы получают текущий класс в качестве первого аргумента. Создайте экземпляр этого cls, а не фиксированного базового класса.

class ServiceDB:
    @classmethod
    async def init(cls, settings):
        self = cls()  # cls is the *current* class, not just ServiceDB
        self.pool = await asyncpg.create_pool(
            database=settings["POSTGRES_DB"],
            user=settings["POSTGRES_USER"],
            password=settings["POSTGRES_PASSWORD"],
            host=settings["DB_HOST"],
            port=settings["DB_PORT"],
        )
        return self

Обратите внимание, что в идеале все атрибуты устанавливаются через __init__ вместо отдельного конструктора classmethod. Отдельный конструктор должен просто передавать любые атрибуты, созданные извне.

class ServiceDB:
    def __init__(self, pool):
        self.pool = pool

    @classmethod
    async def init(cls, settings, **kwargs):
        pool = await asyncpg.create_pool(
            database=settings["POSTGRES_DB"],
            user=settings["POSTGRES_USER"],
            password=settings["POSTGRES_PASSWORD"],
            host=settings["DB_HOST"],
            port=settings["DB_PORT"],
        )
        return cls(pool=pool, **kwargs)

class ChildWriter(ServiceDB):
    async def write_db(self, query): ...

if __name__ == "__main__":
    settings = {'info': "some connection settings"}
    query = "SELECT * FROM 'table'"
    # call classmethod on class   V
    connection = await ChildWriter.init(settings)
    await connection.write_db(msg, query)
person MisterMiyagi    schedule 23.07.2020
comment
отлично, именно то, что мне было нужно, и спасибо за совет classmethod - person G.M; 23.07.2020