如何将其他参数传递给handle_client协程?

JSS*_*all 3 python python-asyncio aiohttp

将异步用于套接字服务器的推荐方法是:

import asyncio

async def handle_client(reader, writer):
    request = (await reader.read(100)).decode()
    response = "Data received." 
    writer.write(response.encode())

async def main():
    loop.create_task(asyncio.start_server(handle_client, 'localhost', 15555))

loop = asyncio.get_event_loop()
loop.create_task(main())
loop.run_forever()
Run Code Online (Sandbox Code Playgroud)

这可以正常工作,但是现在我需要接收适当的客户端请求,然后使用aiohttp库从第三方的Restful API获取数据。

这需要创建一个会话变量,如下所示:

from aiohttp import ClientSession

session = ClientSession()
Run Code Online (Sandbox Code Playgroud)

但这也应该在协程本身内部,因此我将其放入main中:

async def main():
    session = ClientSession()
    loop.create_task(asyncio.start_server(handle_client, '', 55555))
Run Code Online (Sandbox Code Playgroud)

现在,我需要将会话变量传递给aiohttp get coroutine来获取其余的API数据:

async with session.get(url, params=params) as r:
    try:
        return await r.json(content_type='application/json')
    except aiohttp.client_exceptions.ClientResponseError:
        ....
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果它坚持只具有读取器,写入器参数,而全局变量对协程内部必须存在会话却没有帮助,那么如何将会话变量传递给handle_client协程?

use*_*342 5

您可以使用临时函数或lambda:

async def main():
    session = aiohttp.ClientSession()
    await asyncio.start_server(lambda r, w: handle_client(r, w, session),
                               '', 55555)
Run Code Online (Sandbox Code Playgroud)

之所以lambda可行,是因为尽管从技术上讲,它不是协程,但其行为却与协程类似-它是可调用的,在被调用时会返回协程对象

对于大型程序,您可能更喜欢基于类的方法,该类封装了多个客户端共享的状态,而不必将其从协程传递到协程。例如:

class ClientContext:
    def __init__(self, session):
        self.session = session

    async def handle_client(self, reader, writer):
        # ... here you get reader and writer, but also have
        # session etc as self.session ...

async def main():
    ctx = ClientContext(aiohttp.ClientSession())
    await asyncio.start_server(ctx.handle_client), '', 55555)
Run Code Online (Sandbox Code Playgroud)