Чем отличаются генераторы и корутины в Python

Ответ

Генераторы и корутины в Python — это концептуально схожие сущности, так как обе могут приостанавливать и возобновлять свое выполнение. Однако их основное предназначение и способ использования кардинально различаются.

Генераторы (Generators)

Цель: Производить (produce) последовательность значений для итерации. Они работают как "ленивые" итераторы, вычисляя следующее значение только по запросу.

  • Ключевое слово: yield используется для возврата значения.
  • Поток данных: Однонаправленный. Данные идут из генератора наружу.

Пример:

# Этот генератор производит числа от 1 до n
def count_up_to(n):
    i = 1
    while i <= n:
        yield i
        i += 1

# Используем генератор в цикле for
for number in count_up_to(3):
    print(number) # Выведет 1, 2, 3

Корутины (Coroutines)

Цель: Быть точкой приостановки и возобновления в асинхронных программах. Они позволяют выполнять кооперативную многозадачность, передавая управление event loop'у во время ожидания (например, I/O операции).

  • Ключевые слова: async def для объявления и await для приостановки выполнения до завершения другой корутины.
  • Поток данных: Управление передается между корутинами и event loop'ом.

Пример (современный синтаксис):

import asyncio

# Эта корутина "потребляет" время, имитируя I/O операцию
async def fetch_data(delay):
    print("Начинаю загрузку...")
    await asyncio.sleep(delay) # Приостановка выполнения
    print("Загрузка завершена.")
    return {"data": "some data"}

async def main():
    await fetch_data(2)

# Запуск асинхронного кода
asyncio.run(main())

Итог

Характеристика Генератор Корутина (async/await)
Основная цель Производство данных для итерации Кооперативная многозадачность
Синтаксис def + yield async def + await
Направление Производитель (Producer) Точка приостановки (Awaitable)
Сценарий Ленивые вычисления, работа с памятью Асинхронные I/O операции (сеть, файлы)

Примечание: Исторически корутины можно было создавать на основе генераторов с помощью yield и метода .send(), но с появлением синтаксиса async/await в Python 3.5 этот подход считается устаревшим.