无法从异步函数内部屈服并获得屈服数据

时间:2018-12-27 06:22:31

标签: python python-3.x websocket python-asyncio yield-from

我正在尝试从异步函数内部的函数中获取收益。花了数小时试图弄清楚这一点,并遍历了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)

我想我已经掌握了这一点,并且看到了它们是做同一件事的两种不同方式。

感谢您为我指出了正确的方向!

2 个答案:

答案 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,它将返回错误消息,表明您无法等待生成器。