@ asyncio.coroutine против async def

С asyncio библиотекой, которую я видел,

 @asyncio.coroutine def function(): ... 

а также

 async def function(): ... 

используется взаимозаменяемо.

Есть ли функциональная разница между этими двумя?

  • Команда Python popen. Подождите, пока команда не будет завершена.
  • Как заставить python ждать нажатой клавиши
  • Подождите, пока не закончится определенный процесс (зная «pid»)
  • Как подождать некоторое время в pygame?
  • webdriver ждет появления одного из нескольких элементов
  • Настроить реальный тайм-аут для загрузки страницы в Selenium WebDriver?
  • Ожидание анимации «...», чтобы появляться снова и снова
  • Java FluentWait в Python
  • 3 Solutions collect form web for “@ asyncio.coroutine против async def”

    Да, существуют функциональные различия между нативными сопрограммами, использующими синтаксис asyncio.coroutine async def и asyncio.coroutine основе генератора, используя декоратор asyncio.coroutine .

    Согласно PEP 492 , который вводит синтаксис async def :

    1. Собственные объекты coroutine не реализуют __iter__ и __next__ . Следовательно, они не могут быть повторены или переданы в iter() , list() , tuple() и другие встроенные модули. Они также не могут использоваться в цикле for..in .

      Попытка использовать __iter__ или __next__ на нативном сопрограмме coroutine приведет к типу TypeError.

    2. Обычные генераторы не могут yield from native coroutines : это приведет к типу TypeError.

    3. основанные на генераторе сопрограммы (для асинхронного кода должны быть украшены @asyncio.coroutine ) могут @asyncio.coroutine yield from собственных сопроводительных объектов .

    4. inspect.isgenerator() и inspect.isgeneratorfunction() возвращает False для собственных объектов coroutine и собственных функций coroutine .

    Пункт 1 выше означает, что в то время как функции coroutine, определенные с помощью синтаксиса @asyncio.coroutine могут вести себя как традиционные функции генератора, те, которые определены с синтаксисом async def не могут.

    Вот две минимальные, якобы эквивалентные функции сопрограммы, определенные с помощью двух синтаксисов:

     import asyncio @asyncio.coroutine def decorated(x): yield from x async def native(x): await x 

    Хотя байт-код для этих двух функций почти идентичен:

     >>> import dis >>> dis.dis(decorated) 5 0 LOAD_FAST 0 (x) 3 GET_YIELD_FROM_ITER 4 LOAD_CONST 0 (None) 7 YIELD_FROM 8 POP_TOP 9 LOAD_CONST 0 (None) 12 RETURN_VALUE >>> dis.dis(native) 8 0 LOAD_FAST 0 (x) 3 GET_AWAITABLE 4 LOAD_CONST 0 (None) 7 YIELD_FROM 8 POP_TOP 9 LOAD_CONST 0 (None) 12 RETURN_VALUE 

    … с той лишь разницей, что GET_YIELD_FROM_ITER vs GET_AWAITABLE , они ведут себя совершенно по-разному, когда делается попытка перебора объектов, которые они возвращают:

     >>> list(decorated('foo')) ['f', 'o', 'o'] 

     >>> list(native('foo')) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'coroutine' object is not iterable 

    Очевидно, что 'foo' не является ожидаемым, поэтому попытка вызвать native() с ним не имеет большого смысла, но, надеюсь, ясно, что возвращаемый объект coroutine не является итерируемым, независимо от его аргумента.

    Более подробное исследование синтаксиса async / await Бретта Кэннона: Как работает асинхронный / ждущий процесс в Python 3.5? охватывает эту разницу более подробно.

    async def – новый синтаксис, появившийся в Python 3.5. Вы можете использовать await , async with и async for внутри async def s.

    @coroutine – функциональный аналог для async def но он работает в Python 3.4+ и использует yield from строительства вместо await .

    Для практической перспективы просто никогда не используйте @coroutine если ваш Python равен 3.5+.

    Из Python 3.5 coroutines формально стал отдельным типом и, следовательно, синтаксисом async def , а также await .

    До этого Python 3.4 создавал сопрограммы, обертывая регулярные функции в generators , отсюда и синтаксис декоратора, и больше yield from генератора.

    Python - лучший язык программирования в мире.