Генераторы и итераторы

Генераторы и итераторы — это мощные инструменты Python для работы с последовательностями данных.
Они позволяют эффективно работать с большими объёмами данных, не загружая их полностью в память.

Генераторы и итераторы встречаются в самых разных областях:

  • Обработка больших файлов.

  • Работа с базами данных.

  • Потоковая обработка данных.

  • Генерация бесконечных последовательностей.

  • Фильтрация и преобразование данных.

  • Пайплайны данных.

  • Асинхронное программирование.

  • Тестирование и мокирование.

  • Машинное обучение.

  • Веб-скрейпинг.

Давайте рзберёмся как ими пользоваться!


Итераторы

Итератор — это объект, который позволяет перебирать элементы коллекции (например, списка, словаря или строки) по одному.

Основные понятия:
  • Итерируемый объект (Iterable): Объект, который можно перебирать (например, список, строка, словарь).

  • Итератор (Iterator): Объект, который возвращает элементы по одному с помощью метода __next__().

my_list = [1, 2, 3] my_iter = iter(my_list) # Получаем итератор print(next(my_iter)) # 1 print(next(my_iter)) # 2 print(next(my_iter)) # 3 # print(next(my_iter)) # Ошибка StopIteration
Как это работает:
  1. iter() создаёт итератор из итерируемого объекта.
  2. next() возвращает следующий элемент.
  3. Когда элементы заканчиваются, вызывается исключение StopIteration.

Генераторы

Генератор — это функция, которая возвращает итератор. Она использует ключевое слово yield вместо return. Генератор "запоминает" состояние функции между вызовами.

Пример:
def my_generator(): yield 1 yield 2 yield 3 gen = my_generator() print(next(gen)) # 1 print(next(gen)) # 2 print(next(gen)) # 3 # print(next(gen)) # Ошибка StopIteration
Преимущества генераторов:
  • Ленивые вычисления: Элементы генерируются по мере необходимости, что экономит память.
  • Удобство: Не нужно хранить всю последовательность в памяти.

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


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

Генераторные выражения похожи на списковые включения (list comprehensions), но возвращают генератор вместо списка.

Пример:
# Списковое включение squares_list = [x**2 for x in range(10)] # Создаёт список print(squares_list) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # Генераторное выражение squares_gen = (x**2 for x in range(10)) # Создаёт генератор print(next(squares_gen)) # 0 print(next(squares_gen)) # 1
Преимущества:
  • Экономия памяти, так как элементы генерируются "на лету".


Примеры использования генераторов

Пример 1: Бесконечный генератор
def infinite_sequence(): num = 0 while True: yield num num += 1 gen = infinite_sequence() print(next(gen)) # 0 print(next(gen)) # 1 print(next(gen)) # 2 # И так до бесконечности...
Пример 2: Генератор для чтения файла
def read_large_file(file_path): with open(file_path, "r") as file: for line in file: yield line # Использование for line in read_large_file("large_file.txt"): print(line.strip())

Обратите внимание насколько это красивый пример! Здесь мы не загружаем файл целиком в память, а берём лишь по одной строке и после вывода на экран забываем о взятой ранее строке и берём новую!

Пример 3: Фильтрация данных
def even_numbers(sequence): for num in sequence: if num % 2 == 0: yield num # Использование numbers = range(10) even_gen = even_numbers(numbers) print(list(even_gen)) # [0, 2, 4, 6, 8]

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

Чтобы создать собственный итератор, нужно реализовать методы __iter__() и __next__().

Пример:
class MyIterator: def __init__(self, start, end): self.current = start self.end = end def __iter__(self): return self def __next__(self): if self.current < self.end: self.current += 1 return self.current - 1 raise StopIteration # Использование my_iter = MyIterator(1, 5) for num in my_iter: print(num) # 1, 2, 3, 4

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

  1. Экономия памяти: Генераторы не хранят всю последовательность в памяти.

  2. Ленивые вычисления: Элементы генерируются только тогда, когда они нужны.

  3. Удобство: Генераторы позволяют писать чистый и читаемый код.


Генераторы и итераторы широко используются в Python для решения различных задач, особенно там, где требуется эффективная работа с большими объёмами данных или последовательностями. Вот несколько примеров, где они применяются на практике:


Комментарии

Добавить комментарий

Чтобы оставить комменатрий необходимо Авторизоваться