Ввод асинхронной функции и переход к asyncio.create_task

В своем исследовании я вижу общее мнение, что правильный способ ввода асинхронной функции — это Callable[..., Awaitable[Any]].

В Pycharm я пробую это и получаю эту проблему при переходе на asyncio.create_task

import asyncio
from typing import Callable, Awaitable, Any

def fff(ccc: Callable[..., Awaitable[Any]]):
    return asyncio.create_task(ccc())

Это проблема с Pycharm, или я должен по-другому печатать свои асинхронные функции?

Ваша функция ничего не возвращает

eyllanesc 10.01.2023 19:02

Ффф? Я просто использую это, чтобы обернуть код, чтобы продемонстрировать подсказку типа. Меня это не волнует - это ССС

Shuri2060 10.01.2023 19:05

Не могли бы вы показать свою функцию ccc? или хотя бы подпись его?

no_hex 10.01.2023 19:36
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Привет, люди RPA, это снова я и я несу подарки! В очередном моем приключении о том, как создавать ботов для облегчения рутины. Вот, думаю, стоит...
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
Учебник по веб-скрапингу
Учебник по веб-скрапингу
Привет, ребята... В этот раз мы поговорим о веб-скрейпинге. Целью этого обсуждения будет узнать и понять, что такое веб-скрейпинг, а также узнать, как...
Тонкая настройка GPT-3 с помощью Anaconda
Тонкая настройка GPT-3 с помощью Anaconda
Зарегистрируйте аккаунт Open ai, а затем получите ключ API ниже.
1
3
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Разобьём всё на части:

  1. Когда мы объявляем асинхронную функцию, которая возвращает некоторое значение, мы в основном создаем функцию, как показано в этом примере (Python 3.11):
async def ccc():
    return "Hello World"

type(ccc) # <--- function
  1. Эта функция возвращает объект типа сопрограммы
async def ccc():
    return "Hello World"

type(ccc()) # <--- coroutine, not str!

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

По сути, вызов сопрограммы внутри асинхронной функции ничего не даст, как указано в документах:

Мы говорим, что объект является ожидаемым, если его можно использовать в выражении ожидания. Многие асинхронные API предназначены для приема ожидаемых значений.

Это означает, что ваша функция ccc действительно вызывается, которая получает некоторые параметры «%d» (отсюда многоточие), которая возвращает сопрограмму.

Мягко говоря, подсказка типа выглядит примерно так:

Callable[..., Coroutine]

И вы можете быть более явным с Coroutine, поскольку я не знаю, что возвращает ccc.

Более того, я не уверен, как вы хотите вызывать fff, поскольку он не асинхронный, вам нужно будет сделать его таким и дождаться asyncio.create_task как такового:

import asyncio
from typing import Callable, Coroutine


async def ccc():
    print("Hello")
    await asyncio.sleep(5)
    print("World")
    return 12345


async def fff(random_callable: Callable[..., Coroutine]):
    result = await asyncio.create_task(random_callable())
    print(f"{result=}")


if __name__ == '__main__':
    el = asyncio.get_event_loop()
    el.run_until_complete(fff(ccc))
    el.close()

Примечание. Я создал ccc случайным образом для собственного объяснения, так как вы не указали его в самом вопросе :-)

Правильно понял, спасибо за разъяснение. ccc должен был быть общей функцией async def (как в вашем примере). asyncio.create_task не ожидается и fff не существует async, потому что я создавал минимальный пример фоновой задачи (на самом деле ccc задача будет удалена сборщиком мусора, если я ничего с ней не сделаю). Отредактировал OP, чтобы fff вернул его

Shuri2060 10.01.2023 20:16

Но я также хотел знать, почему ответы (и комментарии), подобные этому, говорят, что вы «должны» использовать Awaitable вместо Coroutine stackoverflow.com/a/59177557/5805389

Shuri2060 10.01.2023 20:16

В моем примере random_callable действительно является вызываемым, и он возвращает сопрограмму, которая сама является ожидаемой в том смысле, что «мы можем ее дождаться», но на самом деле ее питонический тип — Coroutine. Я бы посоветовал прочитать это: stackoverflow.com/questions/36342899/… ветка, поскольку она хорошо объясняет различия между сопрограммами, задачами, sure_future, create_tasks и т. д. (мы могли бы изменить его на random_callable: Callable[..., Awaitable] и просто ждать его напрямую: result = await random_callable()

no_hex 10.01.2023 20:32

Согласно документам, подсказка для Coroutine должна иметь такую ​​форму Coroutine[YieldType, SendType, ReturnType], как Генератор. Вы знаете, почему это так? Если вы не определяете асинхронный генератор, я этого не понимаю. Может быть, я открою новый вопрос, если это не простой однострочный ответ

Shuri2060 10.01.2023 20:52

Я думаю, что это должна быть другая тема :-)

no_hex 10.01.2023 23:09

@Shuri2060 Вот комментарий GVR к Awaitable vs Coroutine . Функции с async def-ed имеют методы send, throw и close в дополнение к __await__, и они требуются для asyncio.create_task. Проверьте хорошее объяснение здесь , прочитайте PEP . Его взаимодействие с генераторами может быть еще более забавным. И играть в REPL, конечно же: async def foo(): {yield|return} None; dir(foo())

SUTerliakov 11.01.2023 16:18

Другие вопросы по теме