itertools
(chain
, zip
, islice
).yield from
: Позволяет делегировать часть генерации другому генератору. Это упрощает код, когда один генератор должен включить в свой поток данные из другого.if
, else
) и циклы для выбора, какие данные выдавать, основываясь на результатах работы других генераторов или внешних данных.more_itertools
предоставляет дополнительные инструменты для работы с итераторами и генераторами, упрощая сложные комбинации.Комбинировать несколько генераторов в Python для создания сложных потоков данных можно несколькими способами. Основные подходы:
Можно создать цепочку генераторов, где выход одного генератора служит входом для следующего. Это достигается путем передачи генератора как аргумента в другой генератор.
def numbers(n):
for i in range(n):
yield i
def square(numbers_gen):
for num in numbers_gen:
yield num * num
def even_numbers(square_gen):
for sq in square_gen:
if sq % 2 == 0:
yield sq
# Использование:
num_gen = numbers(10)
square_gen = square(num_gen)
even_gen = even_numbers(square_gen)
for num in even_gen:
print(num) # Выведет квадраты четных чисел от 0 до 9
yield from
(Delegating to Subgenerators):
Оператор yield from
упрощает делегирование генерации элементов от одного генератора к другому. Он позволяет "передавать" генерацию элементов из подгенератора в вызывающий генератор.
def numbers(n):
for i in range(n):
yield i
def square(numbers_gen):
yield from (num * num for num in numbers_gen) # Используем генераторное выражение
def even_numbers(square_gen):
yield from (sq for sq in square_gen if sq % 2 == 0)
# Использование:
num_gen = numbers(10)
square_gen = square(num_gen)
even_gen = even_numbers(square_gen)
for num in even_gen:
print(num)
В этом примере yield from
упрощает код, позволяя не писать цикл for
вручную для каждой итерации подгенератора.
itertools
:
Модуль itertools
предоставляет множество полезных функций для работы с итераторами и генераторами, таких как:
chain
: Объединяет несколько итераторов в один.zip
: Поэлементно объединяет несколько итераторов.islice
: Возвращает выбранные срезы из итератора.tee
: Создает несколько независимых итераторов из одного.starmap
: Подобен map
, но принимает аргументы из итератора.combinations
, permutations
: Генерируют комбинации и перестановки.
import itertools
def even_numbers(n):
for i in range(n):
if i % 2 == 0:
yield i
def odd_numbers(n):
for i in range(n):
if i % 2 != 0:
yield i
# Объединяем генераторы с помощью itertools.chain
combined_gen = itertools.chain(even_numbers(5), odd_numbers(5))
for num in combined_gen:
print(num) # Выведет: 0 2 4 1 3
Генераторные выражения позволяют компактно создавать новые генераторы "на лету".
numbers = (i for i in range(10)) # Генератор чисел от 0 до 9
even_squares = (x*x for x in numbers if x % 2 == 0) # Генератор квадратов четных чисел
for num in even_squares:
print(num)
async
и await
: (Более продвинутый подход, если требуется асинхронная обработка)
Хотя не являются "традиционными" генераторами, асинхронные генераторы (использующие async def
и yield
) позволяют создавать сопрограммы, которые генерируют данные асинхронно. Это полезно для обработки данных, поступающих, например, из сетевых источников или требующих выполнения I/O операций.
import asyncio
async def async_numbers(n):
for i in range(n):
await asyncio.sleep(0.1) # Имитация задержки
yield i
async def async_square(numbers_gen):
async for num in numbers_gen:
yield num * num
async def main():
async for sq in async_square(async_numbers(5)):
print(sq)
if __name__ == "__main__":
asyncio.run(main())
Выбор подхода зависит от конкретной задачи и требований к читаемости, производительности и асинхронности.