Mixinig异步上下文管理器并直接等待asyncio

bro*_*der 7 python-asyncio python-3.5

如何混合

async with api.open() as o:
    ...
Run Code Online (Sandbox Code Playgroud)

o = await api.open()
Run Code Online (Sandbox Code Playgroud)

在一个功能?

由于第一需要的对象与__aenter____aexit__,但第二要求__await__,这应该是没有发电机await.

我的尝试是:

def AsyncContext(aenter, aexit):

    class AsyncContextClass:

        async def __aenter__(self):

            return await aenter()

        async def __aexit__(self, *args):

            return await aexit(*args)

        def __await__(self):

            return (yield from aenter())

    return AsyncContextClass()
Run Code Online (Sandbox Code Playgroud)

但是__await__如果aenter使用async def(TypeError: cannot 'yield from' a coroutine object in a non-coroutine generator)定义则失败.

它与@asyncio.coroutine装饰器工作正常aenter,但这是"脏".

Jas*_*ohi 11

你可以返回__aenter____await__从你的类__await__:

# vim: tabstop=4 expandtab

import asyncio

class Test(object):

    async def __aenter__(self):
        print("enter")

    async def __aexit__(self, *args):
        print("exit")

    def __await__(self):
        return self.__aenter__().__await__()

async def run():
    async with Test():
        print("hello")

    await Test()

loop = asyncio.get_event_loop()
loop.run_until_complete(run())
loop.close()
Run Code Online (Sandbox Code Playgroud)

输出:

enter
hello
exit
enter
Run Code Online (Sandbox Code Playgroud)