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

时间:2015-12-02 20:22:37

标签: python-asyncio python-3.5

如何混合

async with api.open() as o:
    ...

o = await api.open()

在一个函数中?

首先需要__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()

但如果__await__定义为aenterasync def),则TypeError: cannot 'yield from' a coroutine object in a non-coroutine generator失败。

它适用于@asyncio.coroutine的{​​{1}}装饰器,但这很“脏”。

2 个答案:

答案 0 :(得分:10)

您可以从班级__aenter__返回__await__的{​​{1}}:

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

答案 1 :(得分:0)

在python 3.8.5中,您可以执行以下操作

from httpx import AsyncClient
from asyncio import run


async def main():
    api_base_url = 'https://google.com/'

    api_session_build = AsyncClient(base_url=api_base_url)

    # Enter Async Context manager

    apisession = await api_session_build.__aenter__()

    # Do stuff

    print( await apisession.get('/photos/about/'))

    # Exit Async Context Manager

    await apisession.__aexit__()

run(main())