我正在尝试从异步函数内部的函数中获取收益。花了数小时试图弄清楚这一点,并遍历了Stack Overflow来找到以前回答过的类似问题,但是无法帮助我找到自己的问题的解决方案,我发现自己在这里。
很简单,我想使用Web浏览器和Websocket通过Panoramisk查询Asterisk管理界面。当用户连接到websocket服务器时,它将运行ws_handle方法
async def ws_handle(websocket, path):
await register(websocket)
try:
async for message in websocket:
data = json.loads(message)
...
然后我想检索一些数据,然后传递给客户端。我遇到的问题是我发现我不能说
exts = yield from ExtensionStateList.get(AmiManager)
其中的ExtensionStateList.get函数大致如下:
def get(AmiManager):
queues_details = yield from AmiManager.send_action(
{'Action': 'ExtensionStateList'})
...
val = {
'extensions': EXTENSIONS,
'parks': PARKS,
'paging': PAGING,
'confrences': CONFRENCES,
'apps': APPS,
'misc': MISC
}
return val
我已经以非异步方法在与我的websockets服务器文件不同的另一个测试文件中使用了相同的文件ExtensionStateList.py,如前所示
exts = yield from ExtensionStateList.get(AmiManager)
没有问题,它使用函数返回的值填充exts。
我的研究使我如此反复:
async for a in ExtensionStateList.get(AmiManager):
yield a
但是我不知道如何使用它来填充我想要填充的变量。我已经尝试过:
exts = ''
async for a in ExtensionStatList.get(AmiManager):
exts = exts+a
仅被告知不能将AsyncIO.Future连接到字符串。我也尝试过将return val
换成yield val
,但还是没有运气。
很明显,对我来说,这是我缺乏Python知识的一个缺点。我能做什么?我当时在想,也许我可以将ExtensionStateList.get更改为async,但这会让我回到现在所在的同一条船上吗?
添加
我继续通过StackOverflow进行搜索,发现了以下问题:
What is the difference between @types.coroutine and @asyncio.coroutine decorators?
在我看来,如果我在@asyncio.coroutine
上方的行中添加ws_handle
,就像这样:
@asyncio.coroutine
async def ws_handle(websocket, path):
然后我将能够:
exts = yield from ExtensionStateList.get(AmiManager)
但是,我发现这不起作用,它告诉我无法从异步函数内部屈服。我在误解我在这里阅读的内容吗?还是我可能执行不正确?我在这个方向上正确吗?
按照此处给出的答案:
'yield from' inside async function Python 3.6.5 aiohttp
我也尝试过等待这样的功能:
exts = await ExtensionStateList.get(AmiManager)
但是,Python告诉我,对象生成器不能用于await表达式中。
更多信息
对于那些可能感兴趣的人,这就是我调用ws_handle函数的方式。创建websocket服务器时会调用它,而websocket服务器负责调度/调用? ws_handle函数。
在我看来,它为每个连接的客户端调用一次此功能,并且该功能一直运行到用户断开连接为止。
WebsocketServer = websockets.serve(ws_handle, host, port)
asyncio.get_event_loop().run_until_complete(WebsocketServer)
asyncio.get_event_loop().run_forever()
添加
是的,我再次添加了更多。我已经修改了ExtensionStateList.py,以便在调用get方法时,其性能如下:
async def get(AmiManager):
val = await getInternal(AmiManager)
return val
@asyncio.coroutine
def getInternal(AmiManager):
现在我可以在getInternal函数(以前是我的get函数)内部使用yield from
,并且可以按以下方式调用它并接收日期:
exts = await ExtensionStateList.get(AmiManager)
我想我已经掌握了这一点,并且看到了它们是做同一件事的两种不同方式。
感谢您为我指出了正确的方向!
答案 0 :(得分:1)
您对asyncio语法的更改感到有些困惑。在3.5中,我们转到了异步def并等待。 See this answer for details并注意以下示例:
您需要一个异步生成器。请参见Pep 525和示例代码:
async def ticker(delay, to):
"""Yield numbers from 0 to `to` every `delay` seconds."""
for i in range(to):
yield i
await asyncio.sleep(delay)
答案 1 :(得分:0)
保持想法-我没有弄清楚。根据我在下面的评论,我一定很累,并且误以为该程序无法正常工作。糟糕!
EUREKA!
经过数小时的头发撕裂,文档阅读和几乎流泪之后,我发现@async.coroutine
需要应用到ExtensionStateList.get
方法中,如下所示:
#In ExtensionStateList.py
@asyncio.coroutine
def get(AmiManager):
并且像这样调用该命令时必须等待:
exts = ExtensionStateList.get(AmiManager)
await exts
我发现,如果我仅await exts
而不将其设为asyncio.coroutine,它将返回错误消息,表明您无法等待生成器。