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

Ответ

Основное синтаксическое различие заключается в ключевых словах, используемых для их определения и управления.

  1. Генераторы (Generators):

    • Определяются с помощью стандартной функции def.
    • Используют ключевое слово yield для приостановки выполнения и возврата значения. При следующем вызове выполнение возобновляется с места остановки.
    • Цель: Создание итераторов для ленивого вычисления последовательностей.
    def number_generator(n):
        """Генератор, который выдает числа от 0 до n-1."""
        for i in range(n):
            yield i
    
    # Использование
    for num in number_generator(3):
        print(num)  # Выведет 0, 1, 2
  2. Корутины (Coroutines):

    • Определяются с помощью async def.
    • Используют ключевое слово await для приостановки своего выполнения и передачи управления другой корутине (или Future/Task).
    • Цель: Реализация кооперативной многозадачности для асинхронных операций (например, I/O).
    import asyncio
    
    async def fetch_data(url):
        """Корутина, имитирующая асинхронный сетевой запрос."""
        print(f"Начинаю загрузку с {url}...")
        await asyncio.sleep(1) # Приостановка для имитации I/O
        print(f"Загрузка с {url} завершена.")
        return {"data": "some data"}
    
    # Использование
    async def main():
        await fetch_data("https://example.com")
    
    asyncio.run(main())

Кратко: генераторы используют yield для производства данных, а корутины — await для ожидания результата другой асинхронной операции.

Ответ 18+ 🔞

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

Основная разница, блядь, в том, какими словами их объявляют и кто из них на что способен.

  1. Генераторы (Generators):

    • Пишешь обычной функцией, через def.
    • Внутри используешь волшебное слово yield. Оно такое: "На, держи значение, но я тут присяду, отдышусь, а потом продолжу с этого же места, когда меня позовешь снова".
    • Зачем нужны: Чтобы не грузить в память овердохуища данных сразу, а выдавать по кусочку, лениво. Итератор, одним словом.
    def number_generator(n):
        """Генератор, который выдает числа от 0 до n-1."""
        for i in range(n):
            yield i
    
    # Использование
    for num in number_generator(3):
        print(num)  # Выведет 0, 1, 2
  2. Корутины (Coroutines):

    • Вот это уже не просто функция, это async def. Сразу видно — птица высокого полета.
    • Их конёк — слово await. Оно такое: "Слушай, я тут встану на паузу, пойду погуляю, пока ты (какая-нибудь другая корутина, операция ввода-вывода) делаешь своё дело. Как закончишь — свисти, я вернусь и продолжу".
    • Зачем нужны: Чтобы не ждать, как лох, пока диск скрипит или сеть тормозит. Кооперативная многозадачность, ёпта! Пока одна корутина ждет ответа от сервера, другая может работать.
    import asyncio
    
    async def fetch_data(url):
        """Корутина, имитирующая асинхронный сетевой запрос."""
        print(f"Начинаю загрузку с {url}...")
        await asyncio.sleep(1) # Приостановка для имитации I/O
        print(f"Загрузка с {url} завершена.")
        return {"data": "some data"}
    
    # Использование
    async def main():
        await fetch_data("https://example.com")
    
    asyncio.run(main())

Короче, если на пальцах: генератор через yield выдает данные, а корутина через await ждет, пока другие закончат свою работу. Совершенно разные, блядь, парадигмы, хотя внешне и похожи на приостановку выполнения. Вот такая, блядь, матчасть.