Что произойдет, если вызвать асинхронную функцию в Python без await?

Ответ

Вызов асинхронной функции (корутины) без ключевого слова await не запустит её выполнение. Вместо результата вернётся объект корутины (coroutine object).

Этот объект представляет собой "рецепт" для выполнения асинхронной операции, который должен быть передан в цикл событий (event loop) для реального запуска.

Последствия:

  1. Код не выполняется: Логика внутри асинхронной функции не будет исполнена в момент вызова.
  2. Предупреждение RuntimeWarning: Начиная с Python 3.7, интерпретатор выдаст предупреждение RuntimeWarning: coroutine '...' was never awaited, чтобы помочь отловить эту частую ошибку.
  3. Потенциальные баги: Программа будет работать некорректно, так как ожидаемое действие (например, сетевой запрос или работа с файлом) не произойдет.

Пример:

import asyncio

async def fetch_data():
    print("Начинаю загрузку данных...")
    await asyncio.sleep(1) # Имитация I/O операции
    print("Данные загружены!")
    return {"data": 123}

async def main():
    print("Вызов без await:")
    coro_obj = fetch_data() # Код внутри fetch_data() НЕ выполняется
    print(f"Получен объект: {coro_obj}")
    # Чтобы избежать RuntimeWarning, можно "забыть" задачу
    # asyncio.create_task(coro_obj)

    print("nВызов с await:")
    result = await fetch_data() # Код выполняется, ожидаем завершения
    print(f"Получен результат: {result}")

asyncio.run(main())

Вывод:

Вызов без await:
Получен объект: <coroutine object fetch_data at 0x...>

Вызов с await:
Начинаю загрузку данных...
Данные загружены!
Получен результат: {'data': 123}

Ответ 18+ 🔞

Эй, слушай, вот смотри, тут такая дичь, блядь. Если ты вызываешь асинхронную функцию, эту самую корутину, и не пишешь перед ней await — она нихуя не запустится, понимаешь? Вообще. Вместо результата ты получишь какой-то ёбаный объект корутины, типа такого coroutine object.

Этот объект — он как рецепт борща, который ты просто прочитал, но кастрюлю на плиту не поставил. Чтобы борщ сварился, рецепт надо отдать в цикл событий, этот самый event loop, чтобы он там всё и замутил.

Что будет, если накосячить:

  1. Код не выполнится: Вся логика внутри функции останется на бумаге, в рот меня чих-пых! Никаких запросов, никаких операций — тишина.
  2. Получишь по шапке: Начиная с Python 3.7, интерпретатор тебе так вежливо намекнёт: RuntimeWarning: coroutine '...' was never awaited. Мол, чувак, ты забыл её запустить, пидарас шерстяной.
  3. Баги на ровном месте: Программа будет вести себя как пизда с ушами, потому что действия, на которые ты рассчитывал, просто не произойдут.

Смотри, как это выглядит на практике:

import asyncio

async def fetch_data():
    print("Начинаю загрузку данных...")
    await asyncio.sleep(1) # Прикидываемся, что что-то тяжёлое делаем
    print("Данные загружены!")
    return {"data": 123}

async def main():
    print("Вызов без await:")
    coro_obj = fetch_data() # Внутри fetch_data() нихуя не происходит!
    print(f"Получен объект: {coro_obj}")
    # Если хочешь избежать предупреждения, но тебе похуй на результат, можно так
    # asyncio.create_task(coro_obj)

    print("nВызов с await:")
    result = await fetch_data() # А вот тут всё работает, ждём завершения
    print(f"Получен результат: {result}")

asyncio.run(main())

И что на выходе, блядь:

Вызов без await:
Получен объект: <coroutine object fetch_data at 0x...>

Вызов с await:
Начинаю загрузку данных...
Данные загружены!
Получен результат: {'data': 123}

Видишь разницу? В первом случае просто получил какую-то хуйню в переменную, а во втором — всё сделалось как надо. Не забывай про await, а то так и будешь с рецептом борща по кухне ходить, а есть нечего.