簡體   English   中英

使用aiohttp嵌套“與...同步”

[英]nested “async with” using aiohttp

我想創建一個使用aiohttp進行API調用的調度程序類。 我嘗試了這個:

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__函數的第二種方法:

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

效果很好。 這是一個好結構嗎? 它不遵循如何使用aiohttp的示例。 還想知道為什么第一種方法不起作用?

您不能使用with一個函數里,並有上下文管理器保持打開狀態,沒有。 當您使用return退出__aenter__協程時with with aiohttp.ClientSession() as session:塊將立即退出!

對於特定情況,進入aiohttp.ClientSession()上下文管理器aiohttp.ClientSession() 返回self 因此,對於該類型 ,只需創建實例並將其存儲在self.session ,然后等待self.session.close()就可以了,是的。

嵌套異步上下文管理器的一般模式是從您自己的此類方法等待嵌套異步上下文管理器的__aenter____aexit__方法(並可能傳遞異常信息):

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__屬性:

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

您可以從外部管理該依賴關系:

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鏈的async with變得太荒謬時,可以使用AsyncExitStack

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!")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM