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

Как можно взаимодействовать с генератором?

2.2 Middle🔥 151 комментариев
#Python Core

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

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

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

Как можно взаимодействовать с генератором?

Генераторы в Python — это мощный инструмент для работы с последовательностями данных. Вот все способы взаимодействия с ними:

1. Базовое создание генератора через функцию

Генератор создается функцией с yield вместо return:

def simple_generator():
    yield 1
    yield 2
    yield 3

# Создаём генератор
gen = simple_generator()
print(type(gen))  # <class 'generator'>

# Берём элементы один за другим
print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3

# После последнего элемента выбросится StopIteration
try:
    print(next(gen))
except StopIteration:
    print("Генератор исчерпан")

2. Итерация по генератору в цикле

Самый удобный способ — использовать for:

def count_to_five():
    for i in range(1, 6):
        yield i

gen = count_to_five()

# Итерируем
for value in gen:
    print(value)  # Выведет 1, 2, 3, 4, 5

# Генератор исчерпан
for value in gen:
    print(value)  # Ничего не выведет

3. Распаковка генератора в список

Если нужны все значения сразу:

def fibonacci(n):
    """Генерирует первые n чисел Фибоначчи"""
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

# Распаковка в список
fib_list = list(fibonacci(10))
print(fib_list)  # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

# Или распаковка в переменные
a, b, c, *rest = fibonacci(10)
print(a, b, c)  # 0 1 1
print(rest)     # [2, 3, 5, 8, 13, 21, 34]

4. Использование next() с default значением

Чтобы избежать исключения StopIteration:

def small_generator():
    yield 1
    yield 2

gen = small_generator()

print(next(gen))                    # 1
print(next(gen))                    # 2
print(next(gen, "default"))         # "default" вместо ошибки
print(next(gen, None))              # None

5. Отправка значений в генератор

Можно отправлять данные в генератор через send():

def echo_generator():
    print("Генератор запущен")
    while True:
        value = yield  # Получаем значение
        print(f"Получено: {value}")

gen = echo_generator()

# Первый next() нужен для инициализации
next(gen)

# Теперь можем отправлять значения
gen.send("Hello")   # Выведет: Получено: Hello
gen.send("World")   # Выведет: Получено: World
gen.send(42)        # Выведет: Получено: 42

6. Двусторонняя коммуникация с генератором

Передача значения в yield и получение результата:

def power_calculator():
    """Калькулятор, который возводит в степень"""
    power = 1
    while True:
        number = yield power  # Возвращаем результат и получаем число
        power = number ** 2

gen = power_calculator()

print(next(gen))           # 1 (начальное значение)
print(gen.send(2))         # 4 (2^2)
print(gen.send(3))         # 9 (3^2)
print(gen.send(5))         # 25 (5^2)

7. Выброс исключений в генератор

Можно отправить исключение в генератор:

def resilient_generator():
    try:
        yield 1
        yield 2
        yield 3
    except ValueError as e:
        print(f"Поймано исключение: {e}")
        yield "error_handled"

gen = resilient_generator()

print(next(gen))                    # 1
print(next(gen))                    # 2
print(gen.throw(ValueError, "Ошибка!"))  # Поймано исключение: Ошибка!
                                    # error_handled

8. Закрытие генератора

Можно явно закрыть генератор:

def cleanup_generator():
    try:
        yield "processing"
        yield "more processing"
    finally:
        print("Генератор закрывается, чистим ресурсы")

gen = cleanup_generator()

print(next(gen))  # "processing"
gen.close()       # Вызывает finally блок

try:
    next(gen)
except StopIteration:
    print("Генератор закрыт")

9. Выражения-генераторы (generator expressions)

Компактный способ создания генератора:

# Вместо функции с yield
squares = (x**2 for x in range(10))

print(next(squares))      # 0
print(next(squares))      # 1
print(next(squares))      # 4

# Или используй в цикле
for square in (x**2 for x in range(10)):
    print(square)  # 0, 1, 4, 9, 16, ...

# В функциях для фильтрации
even_numbers = (x for x in range(100) if x % 2 == 0)
print(sum(even_numbers))  # Сумма всех чётных чисел до 100

10. Цепочка генераторов

Комбинирование нескольких генераторов:

from itertools import chain

def gen1():
    yield 1
    yield 2

def gen2():
    yield 3
    yield 4

# Объединение
combined = chain(gen1(), gen2())

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

11. Практический пример: чтение большого файла

Генераторы полезны для экономии памяти:

def read_large_file(filepath, batch_size=1000):
    """Читает файл батчами без загрузки в память"""
    with open(filepath, 'r') as file:
        batch = []
        for line in file:
            batch.append(line.strip())
            if len(batch) == batch_size:
                yield batch
                batch = []
        if batch:  # Последний батч
            yield batch

# Использование
for lines in read_large_file('huge_file.txt'):
    process_batch(lines)  # Обрабатываем по 1000 строк

12. Корутины с @contextmanager

Для управления ресурсами:

from contextlib import contextmanager

@contextmanager
def database_connection():
    """Генератор, управляющий подключением к БД"""
    conn = connect_to_db()
    try:
        yield conn
    finally:
        conn.close()

# Использование
with database_connection() as conn:
    result = conn.query("SELECT * FROM users")

13. itertools для работы с генераторами

Полезные функции из стандартной библиотеки:

from itertools import cycle, repeat, takewhile, dropwhile

# cycle — бесконечный цикл
colors = cycle(['red', 'green', 'blue'])
print(next(colors))  # red
print(next(colors))  # green
print(next(colors))  # blue
print(next(colors))  # red (снова)

# repeat — повторить значение N раз
for value in repeat("x", 3):
    print(value)  # x, x, x

# takewhile — брать пока условие верно
data = takewhile(lambda x: x < 5, range(10))
print(list(data))  # [0, 1, 2, 3, 4]

# dropwhile — пропускать пока условие верно
data = dropwhile(lambda x: x < 5, range(10))
print(list(data))  # [5, 6, 7, 8, 9]

Рекомендации:

  • next() — для получения одного элемента
  • for цикл — стандартный способ итерации
  • list() — если нужны все элементы
  • send() — для двусторонней коммуникации
  • close() — для явного закрытия
  • itertools — для сложных операций
  • @contextmanager — для управления ресурсами

Генераторы экономят память и повышают производительность при работе с большими данными.

Как можно взаимодействовать с генератором? | PrepBro