← Назад к вопросам

В чем синтаксическая разница генератора и корутины?

2.0 Middle🔥 91 комментариев
#Python Core#Асинхронность и многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Синтаксическая разница между генератором и корутиной

Хотя генераторы и корутины похожи в концепции (обе приостанавливают выполнение), их синтаксис в Python кардинально отличается и легко различить.

Генератор

Генератор определяется с помощью yield:

def simple_generator():
    print("Start")
    yield 1
    print("Middle")
    yield 2
    print("End")
    yield 3

# Использование
gen = simple_generator()
print(next(gen))  # "Start", затем 1
print(next(gen))  # "Middle", затем 2
print(next(gen))  # "End", затем 3

Синтаксис генератора:

  • Используется ключевое слово yield (не async)
  • Определение: def function_name():
  • Вызов: next(gen) или gen.send(value)
  • Тип объекта: generator object

Корутина (современная)

Корутина определяется с помощью async def и await:

async def simple_coroutine():
    print("Start")
    await asyncio.sleep(1)
    print("Middle")
    await asyncio.sleep(1)
    print("End")
    return 42

# Использование
import asyncio

result = await simple_coroutine()
print(result)  # 42

# Или
asyncio.run(simple_coroutine())

Синтаксис корутины:

  • Используется async def (не просто def)
  • Внутри используется await (не yield)
  • Вызов: await coroutine() (не next())
  • Тип объекта: coroutine object

Таблица сравнения синтаксиса

АспектГенераторКорутина
Определениеdef func():async def func():
Приостановкаyield valueawait awaitable
Вызовnext(gen)await coro()
Типичное использованиеИтерация, потоки данныхАсинхронные операции
Требует event loopНетДа
Тип объектаgeneratorcoroutine

Примеры рядом

# ГЕНЕРАТОР
def number_generator(n):
    for i in range(n):
        print(f"Generating {i}")
        yield i

gen = number_generator(3)
print(next(gen))  # "Generating 0", выводит 0
print(next(gen))  # "Generating 1", выводит 1

# КОРУТИНА
async def fetch_number(n):
    print(f"Fetching {n}")
    await asyncio.sleep(1)
    return n

import asyncio
result = await fetch_number(5)  # "Fetching 5", выводит 5

Синтаксис yield от vs await

В Python 3.4 попытались использовать yield from для корутин:

# СТАРЫЙ СТИЛЬ (Python 3.4) - корутина через генератор
@asyncio.coroutine
def old_style_coroutine():
    result = yield from asyncio.sleep(1)
    return "Done"

# НОВЫЙ СТИЛЬ (Python 3.5+) - настоящая корутина
async def new_style_coroutine():
    result = await asyncio.sleep(1)
    return "Done"

# yield from - это синтаксис генератора
# await - это синтаксис корутины

Проверка типа

import inspect

# ГЕНЕРАТОР
def my_generator():
    yield 1

gen = my_generator()
print(inspect.isgenerator(gen))  # True
print(inspect.iscoroutine(gen))  # False

# КОРУТИНА
async def my_coroutine():
    await asyncio.sleep(0)

coro = my_coroutine()
print(inspect.isgenerator(coro))  # False
print(inspect.iscoroutine(coro))  # True

Итерирование vs Awaiting

# ГЕНЕРАТОР - используется в цикле или next()
def gen():
    yield 1
    yield 2
    yield 3

for value in gen():
    print(value)  # 1, 2, 3

# КОРУТИНА - используется с await
async def coro():
    await asyncio.sleep(1)
    return 42

await coro()  # Возвращает 42

# Попробовать итерировать корутину - ОШИБКА!
for value in coro():  # TypeError!
    pass

Generator Expression vs Async Generator

# ОБЫЧНОЕ ВЫРАЖЕНИЕ генератора
gen = (x * 2 for x in range(5))
print(next(gen))  # 0

# АСИНХРОННЫЙ генератор (Python 3.6+)
async def async_gen():
    for i in range(5):
        await asyncio.sleep(0.1)
        yield i * 2

# Использование асинхронного генератора
async for value in async_gen():
    print(value)  # 0, 2, 4, 6, 8

Синтаксис отправки значений

# ГЕНЕРАТОР - можно отправить значение через send()
def gen_with_send():
    x = yield 1
    print(f"Got: {x}")
    yield 2

gen = gen_with_send()
print(next(gen))  # 1
print(gen.send(100))  # "Got: 100", затем 2

# КОРУТИНА - send() не используется с await
async def coro():
    await asyncio.sleep(0)
    return 42

# Нет способа отправить значение в корутину
# Используются только параметры функции

Синтаксис исключений

# ГЕНЕРАТОР - обработка через throw()
def gen_error():
    try:
        yield 1
        yield 2
    except ValueError as e:
        print(f"Caught: {e}")
        yield 3

gen = gen_error()
print(next(gen))  # 1
print(gen.throw(ValueError("Error")))  # "Caught: Error", затем 3

# КОРУТИНА - обычная try/except
async def coro_error():
    try:
        await something()
    except ValueError as e:
        print(f"Caught: {e}")

Резюме синтаксических различий

ОперацияГенераторКорутина
Определениеdefasync def
Приостановкаyieldawait
Делегированиеyield fromнет (используй await)
Запускnext()await
Отправка значенияsend()нет
Выброс исключенияthrow()try/except
Итерацияfor item in genasync for item in coro
Type checkinspect.isgenerator()inspect.iscoroutine()

Выводы

  • Генератор: yield, next(), можно использовать в обычных циклах
  • Корутина: async def, await, требует event loop
  • Синтаксис несовместим: нельзя смешивать yield и await
  • Цель разная: генератор для потоков данных, корутина для асинхрона
В чем синтаксическая разница генератора и корутины? | PrepBro