如何在 __init__ 中使用 await 设置类属性

新手上路,请多包涵

如何在构造函数或类主体中使用 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'

或带有类 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()

原文由 uralbash 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.7k
2 个回答

大多数魔术方法并非设计用于 async def / await 通常,您应该只使用 await 内部的专用魔术方法 __aiter__ , __anext__ , __aenter__ , and __aexit__ .在其他魔术方法中使用它要么根本不起作用,就像 __init__ 的情况一样(除非您使用此处其他答案中描述的一些技巧),否则将迫使您始终使用触发魔术的任何东西异步上下文中的方法调用。

现有 asyncio 库倾向于通过以下两种方式之一处理此问题:首先,我已经看到使用的工厂模式( 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__ 问题。我还没有看到在野外进行异步调用的类变量,我记得,所以我不知道是否出现了任何完善的模式。

原文由 dano 发布,翻译遵循 CC BY-SA 4.0 许可协议

另一种方法,对于有趣的人:

 class aobject(object):
    """Inheriting this class allows you to define an async __init__.

    So you can create objects by doing something like `await MyClass(params)`
    """
    async def __new__(cls, *a, **kw):
        instance = super().__new__(cls)
        await instance.__init__(*a, **kw)
        return instance

    async def __init__(self):
        pass

#With non async super classes

class A:
    def __init__(self):
        self.a = 1

class B(A):
    def __init__(self):
        self.b = 2
        super().__init__()

class C(B, aobject):
    async def __init__(self):
        super().__init__()
        self.c=3

#With async super classes

class D(aobject):
    async def __init__(self, a):
        self.a = a

class E(D):
    async def __init__(self):
        self.b = 2
        await super().__init__(1)

# Overriding __new__

class F(aobject):
    async def __new__(cls):
        print(cls)
        return await super().__new__(cls)

    async def __init__(self):
        await asyncio.sleep(1)
        self.f = 6

async def main():
    e = await E()
    print(e.b) # 2
    print(e.a) # 1

    c = await C()
    print(c.a) # 1
    print(c.b) # 2
    print(c.c) # 3

    f = await F() # Prints F class
    print(f.f) # 6

import asyncio
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

原文由 khazhyk 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题