2

我正在尝试从异步函数中的函数中获取。花了几个小时试图解决这个问题并遍历 Stack Overflow 以找到以前回答但无法帮助我找到解决自己问题的类似问题,我发现自己在这里。

很简单,我想使用 Web 浏览器和 Websockets 通过 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 vala yield val,再次没有运气。

显然,对我来说,这是我缺乏 Python 知识的一个缺点。我能做些什么?我在想也许我可以将 ExtensionStateList.get 更改为异步,但这会让我回到我现在所处的同一条船上?

此外

我继续翻遍 StackOverflow,发现了以下问题:

@types.coroutine 和 @asyncio.coroutine 装饰器有什么区别?

在我看来,也许如果我@asyncio.coroutine在上面的行中添加ws_handle,如下所示:

@asyncio.coroutine
async def ws_handle(websocket, path):

然后我将能够:

exts = yield from ExtensionStateList.get(AmiManager)

但是,我发现这不起作用,它告诉我不能从异步函数内部产生。我是否误解了我在这里阅读的内容?或者我可能没有正确实施它?我在正确的轨道上吗?

根据此处给出的答案:

'yield from' 异步函数 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):

我现在可以yield from在 getInternal 函数中使用 internal ,这以前是我的 get 函数,我可以调用它并按以下方式接收日期:

exts = await ExtensionStateList.get(AmiManager)

我想我已经掌握了这一点,并且我看到了它们是如何以两种不同的方式来做几乎相同的事情。

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

4

2 回答 2

1

You are confused a little by the change in asyncio syntax. In 3.5 we moved to async def and await. See this answer for details and note the example below:

You want an async generator. See Pep 525 and the example code:

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)
于 2018-12-27T23:05:30.917 回答
0

保持这个想法 - 我没有弄明白。根据我在下面的评论,我一定是累了,误以为程序工作出错了。哎呀。

尤里卡!

经过几个小时的头发撕裂,文档阅读和几乎眼泪,我发现@async.coroutine需要将其应用于这样的ExtensionStateList.get方法:

#In ExtensionStateList.py
@asyncio.coroutine
def get(AmiManager):

并且在像这样调用该命令时我必须等待:

exts = ExtensionStateList.get(AmiManager)
await exts

我发现如果我只是await exts不让它成为 asyncio.coroutine,它会返回错误,指出你不能等待生成器。

于 2018-12-27T09:04:15.910 回答