Python Генераторы

Генераторы в Python — это особый тип итераторов, которые позволяют создавать последовательности значений по требованию, не сохраняя их все в памяти одновременно. Генераторы реализуют ленивое вычисление и являются мощным инструментом для работы с большими данными.

Способы создания генераторов

  • Generator functions — функции с yield
  • Generator expressions — генераторные выражения
  • Generator classes — классы с __iter__ и __next__

Пример функции-генератора

 1def countdown(n):
 2    while n > 0:
 3        yield n
 4        n -= 1
 5
 6# Использование
 7for num in countdown(5):
 8    print(num)
 9
10# Или создание объекта генератора
11gen = countdown(3)
12print(next(gen))  # 3
13print(next(gen))  # 2
14print(next(gen))  # 1

Генераторные выражения

 1# Генераторное выражение
 2squares = (x**2 for x in range(10))
 3
 4# Эквивалентная функция-генератор
 5def squares_func():
 6    for x in range(10):
 7        yield x**2
 8
 9# Использование
10for square in squares:
11    print(square)
12
13# Генераторы можно использовать в функциях
14sum_of_squares = sum(x**2 for x in range(10))
15print(sum_of_squares)  # 285

Преимущества генераторов

  • Память — экономят память, создавая значения по требованию
  • Производительность — ленивое вычисление
  • Бесконечные последовательности — могут создавать бесконечные итерации
  • Композиция — легко комбинировать с другими генераторами

Пример бесконечного генератора

 1def fibonacci():
 2    a, b = 0, 1
 3    while True:
 4        yield a
 5        a, b = b, a + b
 6
 7# Получение первых 10 чисел Фибоначчи
 8fib = fibonacci()
 9for i in range(10):
10    print(next(fib))
11
12# Или с помощью itertools
13import itertools
14fib_numbers = list(itertools.islice(fibonacci(), 10))
15print(fib_numbers)

Методы генераторов

 1def my_generator():
 2    try:
 3        value = yield "Первое значение"
 4        yield f"Получено: {value}"
 5    except GeneratorExit:
 6        print("Генератор закрывается")
 7    except Exception as e:
 8        print(f"Получено исключение: {e}")
 9
10gen = my_generator()
11print(next(gen))  # Первое значение
12
13# send() - отправка значения в генератор
14print(gen.send("Привет"))  # Получено: Привет
15
16# throw() - отправка исключения
17gen = my_generator()
18next(gen)
19gen.throw(ValueError("Ошибка"))
20
21# close() - закрытие генератора
22gen = my_generator()
23next(gen)
24gen.close()

Практические примеры

 1# Чтение больших файлов
 2def read_large_file(file_path):
 3    with open(file_path, 'r') as file:
 4        for line in file:
 5            yield line.strip()
 6
 7# Фильтрация данных
 8def filter_even_numbers(numbers):
 9    for num in numbers:
10        if num % 2 == 0:
11            yield num
12
13# Pipeline обработки данных
14def process_data(data):
15    for item in data:
16        # Обработка каждого элемента
17        processed = item.upper()
18        yield processed
19
20# Использование pipeline
21numbers = range(1, 11)
22even_numbers = filter_even_numbers(numbers)
23processed_data = process_data(str(n) for n in even_numbers)
24
25for item in processed_data:
26    print(item)  # 2, 4, 6, 8, 10

Генераторы vs Списки

 1import sys
 2
 3# List comprehension - создает весь список в памяти
 4squares_list = [x**2 for x in range(1000000)]
 5print(f"Размер списка: {sys.getsizeof(squares_list)} байт")
 6
 7# Generator expression - создает генератор
 8squares_gen = (x**2 for x in range(1000000))
 9print(f"Размер генератора: {sys.getsizeof(squares_gen)} байт")
10
11# Генератор занимает значительно меньше памяти

FAQ

В чем разница между return и yield?

return завершает функцию, yield приостанавливает выполнение и возвращает значение, сохраняя состояние функции для продолжения.

Когда использовать генераторы?

Используй генераторы при работе с большими данными, бесконечными последовательностями или когда нужно экономить память.