Asyncio中的请求 - 关键字参数

时间:2014-05-30 04:11:33

标签: python python-requests python-asyncio

我使用 asyncio requests 模块进行异步HTTP请求。

我可以这样做一个GET请求:

@asyncio.coroutine
def do_checks():
    loop = asyncio.get_event_loop()
    req = loop.run_in_executor(None, requests.get, 'https://api.github.com/user')
    resp = yield from req
    print(resp.status_code)
loop = asyncio.get_event_loop()
loop.run_until_complete(do_checks())

但是,我需要在请求中支持Basic HTTP Auth(described here)。

根据文档, url auth 都是requests.get()的命名参数。

但是,如果我执行此操作(请注意添加 url ='' auth ='' ) :

@asyncio.coroutine
def do_checks():
    loop = asyncio.get_event_loop()
    req = loop.run_in_executor(None, requests.get, url='https://api.github.com/user', auth=HTTPBasicAuth('user', 'pass'))
    resp = yield from req
    print(resp.status_code)
loop = asyncio.get_event_loop()
loop.run_until_complete(do_checks())

我收到此错误:

TypeError: run_in_executor() got an unexpected keyword argument 'url'

在asyncio.run_in_executor()的原型中,支持其他参数:

BaseEventLoop.run_in_executor(executor, callback, *args)

requests.get()明确支持命名参数(get,auth等)。怎么了?

2 个答案:

答案 0 :(得分:6)

有两种方法可以做到这一点。创建包装函数,或者只使用会话来提供身份验证。

使用会话:

@asyncio.coroutine
def do_checks():
    loop = asyncio.get_event_loop()
    session = requests.Session()
    session.auth = HTTPBasicAuth('user', 'pass')
    req = loop.run_in_executor(None, session.get, 'https://api.github.com/user')
    resp = yield from req
    print(resp.status_code)

编写一个包装函数(请注意,我在这里使用def是为了清晰起见,但是lambda显然也会起作用):

@asyncio.coroutine
def do_checks():
    def do_req():
        return requests.get('https://api.github.com/user', auth=HTTPBasicAuth('user', 'pass'))
    loop = asyncio.get_event_loop()
    req = loop.run_in_executor(None, do_req)
    resp = yield from req
    print(resp.status_code)

答案 1 :(得分:5)

这实际上是asyncio中的设计决定。来自asyncio / base_events.py的文档字符串:

"""Base implementation of event loop.

The event loop can be broken up into a multiplexer (the part
responsible for notifying us of IO events) and the event loop proper,
which wraps a multiplexer with functionality for scheduling callbacks,
immediately or at a given time in the future.

Whenever a public API takes a callback, subsequent positional
arguments will be passed to the callback if/when it is called.  This
avoids the proliferation of trivial lambdas implementing closures.
Keyword arguments for the callback are not supported; this is a
conscious design decision, leaving the door open for keyword arguments
to modify the meaning of the API call itself.
"""

注意那里的最后一句话。

asyncio PEP也注意到这一点,并建议使用lambda来解决它:

  

此约定特别不支持关键字参数。   关键字参数用于传递有关的可选附加信息   回调。这允许API的优雅演变而无需   担心关键字对被调用者是否重要   某处。如果您有必须使用关键字调用的回调   参数,你可以使用lambda。例如:

     

loop.call_soon(lambda: foo('abc', repeat=42))