Почему я получаю «асинхронное понимание вне асинхронной функции»? - PullRequest
2 голосов
/ 03 февраля 2020

Я использую Python 3.7.4 и этот блок кода (MWE):

import asyncio


async def foo(x):
    await asyncio.sleep(1)
    return [i for i in range(10)]


async def big_foo():
    dict_of_lists = {'A': [i for i in range(10)], 'B': [i for i in range(10)]}
    return {
        key: [
            item
            for list_item in dict_of_lists[key]
            for item in await foo(list_item)
        ]
        for key in ['A', 'B']
    }

Выдает ошибку:

File "filename.py", line 13
    item
    ^
SyntaxError: asynchronous comprehension outside of an asynchronous function

Сообщение об ошибке не очень помогли, потому что это действительно внутри асинхронной функции.

Я решил проблему, определив явные циклы for вместо понимания, как это:

async def big_foo():
    dict_of_lists = {'A': [i for i in range(10)], 'B': [i for i in range(10)]}
    var = {}
    for key in ['A', 'B']:
        var[key] = []
        for list_item in dict_of_lists[key]:
            for item in await foo(list_item):
                var[key].append(item)
    return var

Меня это беспокоит удаление внешнего словаря l oop также удаляет ошибку.

Это работает (не выполняет sh то, что мне нужно, очевидно):

async def other_foo():
    dict_of_lists = {'A': [i for i in range(10)]}
    return [
        item
        for list_item in dict_of_lists['A']
        for item in await foo(list_item)
    ]

1 Ответ

2 голосов
/ 03 февраля 2020

Я нашел ответ. Цитирую коллегу:

Внутреннее понимание асинхронно. Внешний не является. Функция асинхронная. Ошибка вызвана тем, что вы определяете как асинхронное понимание внутри несинхронного контекста - сообщение об ошибке действительно неверно и это известная ошибка.

https://bugs.python.org/issue33346

Я исправил это, установив async for во внешнем понимании. Например:

async def big_foo():
    dict_of_lists = {'A': [i for i in range(10)], 'B': [i for i in range(10)]}
    return {
        key: [
            item
            for list_item in dict_of_lists[key]
            for item in await foo(list_item)
        ]
        async for key in ['A', 'B']
    }

Хотя это удаляет упомянутое SyntaxError, оно вводит TypeError: 'async for' requires an object with __aiter__ method, got tuple. Таким образом, решение было бы определить обертку для него, но это больше похоже на взлом, чем правильное решение.

...