Как правильно выполнить exec () для сопрограммы

Я пишу бота Discord, и у меня проблемы с тестированием асинхронной функции. Я хочу проверить это с помощью exec(), но не могу правильно вызвать функцию.

Я пробовал exec () - использовать функцию как с ожиданием, так и без него. Я просмотрел документацию по API , но это не дало мне глубокого понимания моей проблемы. Используя eval(), он возвращает объект сопрограммы, но не выполняет его.

Exec () выполняется путем обработки сообщения с помощью асинхронной функции.

async def f(message)
    #other stuff
    ...
    ...
    exec(strip2(message.content, "exec"))
    return #exec doesn't return anything, so we return to not send an empty message

Функция async выглядит примерно так:

async def move_message(message_id, old_channel, new_channel):
    """
    check the 20 latest messages in old_channel, and if
    one of them matches the id, move it to new_channel
    """
    print("ok")
    async for message in old_channel.history(limit=20):
        #do stuff
        ...
    print("good!")

Без await выдает следующую ошибку: ...\commands.py:1: RuntimeWarning: coroutine 'move_message' was never awaited С await выдает SyntaxError:

 File "<string>", line 1
    await move_message(message, message.channel, "admin-test-playground")
                     ^
SyntaxError: invalid syntax

Я хочу, чтобы функция выполнялась правильно, хоть что-то печатала. Но ни "хорошо", ни "хорошо!" печатает с тем, что у меня есть сейчас.


person The Bic Pen    schedule 28.04.2019    source источник


Ответы (1)


async и await имеют особый синтаксис. await expr правильно анализирует только в async def контексте. Таким образом, exec("await function()") вызовет SyntaxError, поскольку exec работает путем синтаксического анализа оператора и его выполнения, поэтому он не соблюдает цикл событий.

Следовательно, вы не можете использовать exec в асинхронном коде для вызова асинхронных функций. Это имеет смысл, если вы лучше понимаете, как асинхронные функции работают под капотом, поскольку await изменяет поведение кода больше, чем вызов функции.

Однако, если вы переключитесь на использование eval, код, который у вас был раньше, должен вместо этого вернуть объект сопрограммы, который вы вызываете. Поскольку объекты сопрограмм ожидаются, вы можете использовать это, как вы планировали с exec.

Итак, у вас должно получиться что-то вроде

def f(message):
    await eval(message.lstrip('exec '))

и пусть он работает правильно.

person Edward Minnix    schedule 28.04.2019
comment
Я пробовал использовать eval, но это отправляет ту же синтаксическую ошибку в виде сообщения. неверный синтаксис (‹string›, строка 1) - person The Bic Pen; 28.04.2019
comment
Вам нужно будет удалить await с начала строки - person Edward Minnix; 28.04.2019
comment
Так что-то вроде eval(move_message(1, "bot-playground", "admin-test-playground"))? Я пробовал это раньше, и он возвращает объект сопрограммы, но не выполняется. Я обновлю вопрос, добавив, что я это пробовал. - person The Bic Pen; 28.04.2019
comment
Да в том-то и дело. У вас есть объект сопрограммы, и вам нужно дождаться его. Так что это было бы похоже на await eval('move_message(1, "bot-playground", "admin-test-playground")'). - person Edward Minnix; 28.04.2019