"async with" 在 Python 3.4
"async with" in Python 3.4
aiohttp 入门文档提供了以下客户端示例:
import asyncio
import aiohttp
async def fetch_page(session, url):
with aiohttp.Timeout(10):
async with session.get(url) as response:
assert response.status == 200
return await response.read()
loop = asyncio.get_event_loop()
with aiohttp.ClientSession(loop=loop) as session:
content = loop.run_until_complete(
fetch_page(session, 'http://python.org'))
print(content)
他们为 Python 3.4 用户提供以下注释:
If you are using Python 3.4, please replace await with yield from and
async def with a @coroutine decorator.
如果我按照这些说明操作,我会得到:
import aiohttp
import asyncio
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(10):
async with session.get(url) as response:
return (yield from response.text())
if __name__ == '__main__':
loop = asyncio.get_event_loop()
with aiohttp.ClientSession(loop=loop) as session:
html = loop.run_until_complete(
fetch(session, 'http://python.org'))
print(html)
然而,这不会运行,因为async with
在Python 3.4中不被支持:
$ python3 client.py
File "client.py", line 7
async with session.get(url) as response:
^
SyntaxError: invalid syntax
我如何翻译 async with
语句以使用 Python 3.4?
只是不要将 session.get()
的结果用作上下文管理器;直接将其用作协程。 session.get()
生成的请求上下文管理器通常会 release the request on exit, but so does using response.text()
,所以你可以在这里忽略它:
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(10):
response = yield from session.get(url)
return (yield from response.text())
此处返回的请求包装器没有所需的异步方法(__aenter__
和 __aexit__
),它们在不使用 Python 3.5 时完全省略(参见 relevant source code).
如果在 session.get()
调用和访问 response.text()
等待之间有更多的语句,您可能想要使用 try:..finally:
来释放连接;如果发生异常,Python 3.5 版上下文管理器还会关闭 响应。因为这里需要一个yield from response.release()
,所以在Python 3.4:
之前,这个不能封装在context manager中
import sys
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(10):
response = yield from session.get(url)
try:
# other statements
return (yield from response.text())
finally:
if sys.exc_info()[0] is not None:
# on exceptions, close the connection altogether
response.close()
else:
yield from response.release()
aiohttp
的 examples implemented using 3.4 syntax. Based on json client example 您的函数将是:
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(10):
resp = yield from session.get(url)
try:
return (yield from resp.text())
finally:
yield from resp.release()
更新:
请注意,Martijn 的解决方案适用于简单情况,但在特定情况下可能会导致不良行为:
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(5):
response = yield from session.get(url)
# Any actions that may lead to error:
1/0
return (yield from response.text())
# exception + warning "Unclosed response"
除了异常你还会收到警告"Unclosed response"。这可能会导致复杂应用程序中的连接泄漏。如果您手动调用 resp.release()
/resp.close()
:
就可以避免这个问题
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(5):
resp = yield from session.get(url)
try:
# Any actions that may lead to error:
1/0
return (yield from resp.text())
except Exception as e:
# .close() on exception.
resp.close()
raise e
finally:
# .release() otherwise to return connection into free connection pool.
# It's ok to release closed response:
# https://github.com/KeepSafe/aiohttp/blob/master/aiohttp/client_reqrep.py#L664
yield from resp.release()
# exception only
我认为最好遵循官方示例(和__aexit__
implementation)并显式调用resp.release()
/resp.close()
。
aiohttp 入门文档提供了以下客户端示例:
import asyncio
import aiohttp
async def fetch_page(session, url):
with aiohttp.Timeout(10):
async with session.get(url) as response:
assert response.status == 200
return await response.read()
loop = asyncio.get_event_loop()
with aiohttp.ClientSession(loop=loop) as session:
content = loop.run_until_complete(
fetch_page(session, 'http://python.org'))
print(content)
他们为 Python 3.4 用户提供以下注释:
If you are using Python 3.4, please replace await with yield from and async def with a @coroutine decorator.
如果我按照这些说明操作,我会得到:
import aiohttp
import asyncio
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(10):
async with session.get(url) as response:
return (yield from response.text())
if __name__ == '__main__':
loop = asyncio.get_event_loop()
with aiohttp.ClientSession(loop=loop) as session:
html = loop.run_until_complete(
fetch(session, 'http://python.org'))
print(html)
然而,这不会运行,因为async with
在Python 3.4中不被支持:
$ python3 client.py
File "client.py", line 7
async with session.get(url) as response:
^
SyntaxError: invalid syntax
我如何翻译 async with
语句以使用 Python 3.4?
只是不要将 session.get()
的结果用作上下文管理器;直接将其用作协程。 session.get()
生成的请求上下文管理器通常会 release the request on exit, but so does using response.text()
,所以你可以在这里忽略它:
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(10):
response = yield from session.get(url)
return (yield from response.text())
此处返回的请求包装器没有所需的异步方法(__aenter__
和 __aexit__
),它们在不使用 Python 3.5 时完全省略(参见 relevant source code).
如果在 session.get()
调用和访问 response.text()
等待之间有更多的语句,您可能想要使用 try:..finally:
来释放连接;如果发生异常,Python 3.5 版上下文管理器还会关闭 响应。因为这里需要一个yield from response.release()
,所以在Python 3.4:
import sys
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(10):
response = yield from session.get(url)
try:
# other statements
return (yield from response.text())
finally:
if sys.exc_info()[0] is not None:
# on exceptions, close the connection altogether
response.close()
else:
yield from response.release()
aiohttp
的 examples implemented using 3.4 syntax. Based on json client example 您的函数将是:
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(10):
resp = yield from session.get(url)
try:
return (yield from resp.text())
finally:
yield from resp.release()
更新:
请注意,Martijn 的解决方案适用于简单情况,但在特定情况下可能会导致不良行为:
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(5):
response = yield from session.get(url)
# Any actions that may lead to error:
1/0
return (yield from response.text())
# exception + warning "Unclosed response"
除了异常你还会收到警告"Unclosed response"。这可能会导致复杂应用程序中的连接泄漏。如果您手动调用 resp.release()
/resp.close()
:
@asyncio.coroutine
def fetch(session, url):
with aiohttp.Timeout(5):
resp = yield from session.get(url)
try:
# Any actions that may lead to error:
1/0
return (yield from resp.text())
except Exception as e:
# .close() on exception.
resp.close()
raise e
finally:
# .release() otherwise to return connection into free connection pool.
# It's ok to release closed response:
# https://github.com/KeepSafe/aiohttp/blob/master/aiohttp/client_reqrep.py#L664
yield from resp.release()
# exception only
我认为最好遵循官方示例(和__aexit__
implementation)并显式调用resp.release()
/resp.close()
。