← Назад к вопросам
В чем синтаксическая разница генератора и корутины?
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 value | await awaitable |
| Вызов | next(gen) | await coro() |
| Типичное использование | Итерация, потоки данных | Асинхронные операции |
| Требует event loop | Нет | Да |
| Тип объекта | generator | coroutine |
Примеры рядом
# ГЕНЕРАТОР
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}")
Резюме синтаксических различий
| Операция | Генератор | Корутина |
|---|---|---|
| Определение | def | async def |
| Приостановка | yield | await |
| Делегирование | yield from | нет (используй await) |
| Запуск | next() | await |
| Отправка значения | send() | нет |
| Выброс исключения | throw() | try/except |
| Итерация | for item in gen | async for item in coro |
| Type check | inspect.isgenerator() | inspect.iscoroutine() |
Выводы
- Генератор: yield, next(), можно использовать в обычных циклах
- Корутина: async def, await, требует event loop
- Синтаксис несовместим: нельзя смешивать yield и await
- Цель разная: генератор для потоков данных, корутина для асинхрона