嵌套“与...异步”使用aiohttp [英] nested "async with" using aiohttp
问题描述
我想创建一个使用aiohttp进行API调用的调度程序类。我尝试过这个:
I would like to create a scheduler class that uses aiohttp to make API calls. I tried this:
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:会话已关闭
。 __ aenter __
函数的第二种方法:
but this just results in an error: RuntimeError: Session is closed
. A second approach for the __aenter__
function:
async def __aenter__(self):
self.session = aiohttp.ClientSession()
return self
效果很好。这是一个好结构吗?它不遵循有关如何使用aiohttp的示例。还想知道为什么第一种方法不起作用?
works well. Is this a good construct? It doesn't adhere to examples of how to use aiohttp. Also wondering why the first approach isn't working?
推荐答案
您不能在中使用
在函数内并让上下文管理器保持打开状态,否。当您使用 return
退出<$时,带有aiohttp.ClientSession()作为会话的退出:
c $ c> __ aenter __ 协程!
You can't use with
inside a function and have the context manager remain open, no. The with with aiohttp.ClientSession() as session:
block exits as soon as you use return
to exit the __aenter__
coroutine!
在特定情况下,输入 aiohttp.ClientSession()
上下文管理器除了返回自我
。因此,对于那个类型,只需创建实例并将其存储在 self.session
中,然后等待 self.session。 close()
在这里就足够了,是的。
For the specific case, entering a aiohttp.ClientSession()
context manager does nothing but return self
. So for that type, just creating the instance and storing it in self.session
, and awaiting on self.session.close()
suffices here, yes.
嵌套异步上下文管理器的 general 模式将等待嵌套异步上下文管理器的 __ aenter __
和 __ aexit __
方法来自您自己的此类方法(并且可能会传递异常信息) :
The general pattern for a nested asynchronous context manager is to await the __aenter__
and __aexit__
methods of a nested async context manager from your own such methods (and perhaps pass along the exception information):
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 __
属性,然后进入嵌套上下文管理器:
Technically speaking, you should first assure that there is an actual __aexit__
attribute before entering a nested context manager:
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)
请参见
。异步Context-managers-and-async-with rel = noreferrer>添加了该概念的官方PEP 。
这篇关于嵌套“与...异步”使用aiohttp的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!