首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用aiohttp嵌套“异步”

使用aiohttp嵌套“异步”
EN

Stack Overflow用户
提问于 2018-11-09 15:16:01
回答 2查看 3.9K关注 0票数 6

我希望创建一个使用aiohttp进行API调用的调度器类。我试过这个:

代码语言:javascript
复制
import asyncio
import aiohttp

class MySession:
    def __init__(self):
        self.session = None

    async def __aenter__(self):
        async with aiohttp.ClientSession() as session:
            self.session = session
            return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if self.session:
            await self.session.close()

async def method1():
    async with MySession() as s:
        async with s.session.get("https://www.google.com") as resp:
            if resp.status == 200:
                print("successful call!")

loop = asyncio.get_event_loop()
loop.run_until_complete(method1())
loop.close()

但这只会导致一个错误:RuntimeError: Session is closed

__aenter__函数的第二种方法:

代码语言:javascript
复制
    async def __aenter__(self):
        self.session = aiohttp.ClientSession()
        return self

效果很好。这是个很好的构造吗?它没有遵循如何使用aiohttp的例子。还想知道为什么第一种方法不起作用?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-11-09 15:19:48

您不能在函数中使用with,并且上下文管理器保持打开状态,不行。with with aiohttp.ClientSession() as session:块一旦使用return退出__aenter__协同线就会退出!

对于具体情况,输入一个aiohttp.ClientSession()上下文管理器self。因此,对于该类型,只需创建实例并将其存储在self.session中,在这里等待self.session.close()就足够了,是的。

嵌套异步上下文管理器的一般模式是等待嵌套异步上下文管理器的__aenter____aexit__方法(并且可能传递异常信息):

代码语言:javascript
复制
class MySession:
    def __init__(self):
        self.session = None

    async def __aenter__(self):
        self.session = aiohttp.ClientSession()
        await self.session.__aenter__()
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if self.session:
            return await self.session.__aexit__(exc_type, exc_val, exc_tb)

从技术上讲,在输入嵌套上下文管理器之前,首先应该确保存在一个实际的__aexit__属性:

代码语言:javascript
复制
class MySession:
    def __init__(self):
        self.session = None
        self._session_aexit = None

    async def __aenter__(self):
        self.session = aiohttp.ClientSession()
        self._session_aexit = type(self.session).__aexit__
        await self.session.__aenter__()
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if self.session:
            return await self._session_aexit.__aexit__(
                self.session, exc_type, exc_val, exc_tb)

官方的PEP增加了这个概念

票数 7
EN

Stack Overflow用户

发布于 2019-01-11 12:50:39

您可以在外部管理该依赖关系:

代码语言:javascript
复制
import asyncio
import aiohttp

class MySession:

    def __init__(self, client_session):
        self.session = client_session

    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        pass

async def method1():
    async with aiohttp.ClientSession() as client_session:
        async with MySession(client_session) as s:
            async with s.session.get("https://www.google.com") as resp:
                if resp.status == 200:
                    print("successful call!")

asyncio.run(method1())

async with链变得太荒谬时,可以使用AsyncExitStack

代码语言:javascript
复制
from contextlib import AsyncExitStack

async def method1():
    async with AsyncExitStack() as stack:
        client_session = await stack.enter_async_context(aiohttp.ClientSession())
        s = await stack.enter_async_context(MySession(client_session))
        async with s.session.get("https://www.google.com") as resp:
            if resp.status == 200:
                print("successful call!")
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53228434

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档