我使用 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等)。怎么了?
答案 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))