如何在 __init__ 中使用 await 设置类属性 [英] How to set class attribute with await in __init__

查看:100
本文介绍了如何在 __init__ 中使用 await 设置类属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在构造函数或类主体中定义带有 await 的类?

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

例如我想要的:

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

推荐答案

大多数魔法方法都不是为与 async def/await 一起使用而设计的 - 一般来说,你应该只在专用的异步魔术方法中使用 await - __aiter____anext____aenter____aexit__.在其他魔术方法中使用它要么根本不起作用,就像 __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__ (unless you use some tricks described in other answers here), or will force you to always use whatever triggers the magic method call in an asynchronous context.

现有的 asyncio 库倾向于通过以下两种方式之一处理这个问题:首先,我已经看到使用的工厂模式 (asyncio-redis,例如):

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)

您想在 __init__ 中调用的 aiopg 中的 create_pool 函数实际上正在使用这种模式.

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

这至少解决了 __init__ 问题.我还没有看到我记得的在野外进行异步调用的类变量,所以我不知道是否出现了任何完善的模式.

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.

这篇关于如何在 __init__ 中使用 await 设置类属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆