Итераторы и итерируемые объекты в ООП: __iter__, __next__

🔄 Итерируемые объекты vs Итераторы: в чём разница?

В Python итерируемый объект (iterable) — это любой объект, который можно «прочитать» поэлементно. Например, списки, строки, словари. Но сам по себе он не умеет «запоминать» текущую позицию при переборе.

А итератор — это «движок» перебора, который знает своё текущее состояние. Он «помнит», на каком элементе остановился.

numbers = [1, 2, 3]  # <- iterable (итерируемый объект)
iterator = iter(numbers)  # <- iterator (итератор)
print(next(iterator))  # 1
print(next(iterator))  # 2

🏗️ Как устроены итераторы «под капотом»?

Любой итератор в Python реализует два «магических» метода:

  • __iter__() — возвращает сам объект итератора.
  • __next__() — возвращает следующий элемент или вызывает StopIteration.
class Counter:
    def __init__(self, max_num):
        self.max_num = max_num
        self.current = 0

    def __iter__(self):
        return self  # <- возвращаем сам итератор!

    def __next__(self):
        if self.current < self.max_num:
            self.current += 1
            return self.current
        raise StopIteration  # <- сигнал остановки

counter = Counter(3)
for num in counter:  # работает!
    print(num)  # 1, 2, 3

🔍 Разбираем пример: Итератор для чтения файла

Практичный пример — итератор, который читает файл построчно, не загружая его целиком в память.

class FileLineIterator:
    def __init__(self, filename):
        self.file = open(filename, 'r')

    def __iter__(self):
        return self

    def __next__(self):
        line = self.file.readline()
        if line:
            return line.strip()
        self.file.close()
        raise StopIteration

# Использование:
for line in FileLineIterator('data.txt'):
    print(line)  # Читаем файл лениво!

🎯 Главное правило итераторов

Итератор — одноразовый! После перебора его элементы «заканчиваются».

numbers = [1, 2, 3]
iterator = iter(numbers)
print(list(iterator))  # [1, 2, 3]
print(list(iterator))  # [] 😱 Пусто!

🛠️ Как сделать объект итерируемым?

Если нужно, чтобы ваш класс поддерживал цикл for, достаточно реализовать __iter__(), но не обязательно __next__().

class ShoppingCart:
    def __init__(self):
        self.items = ['яблоко', 'банан', 'апельсин']

    def __iter__(self):
        return iter(self.items)  # делегируем встроенному итератору списка

cart = ShoppingCart()
for item in cart:  # работает!
    print(item)  # яблоко, банан, апельсин

🔥 Продвинутый пример: Бесконечный итератор

Итераторы могут быть бесконечными! Например, генератор случайных чисел.

import random

class RandomNumbers:
    def __iter__(self):
        return self

    def __next__(self):
        return random.randint(1, 100)

# Использование:
for num in RandomNumbers():
    print(num)  # Бесконечный поток чисел!
    if num == 42:  # Условие выхода
        break

🔗 Для углубления в тему рекомендую видео Данилы Бежина: ООП в Python. Там есть разбор итераторов с примерами из реальных проектов.

Скрыть рекламу навсегда

🧠 Учёба без воды и зубрёжки

Закрытый Boosty с наработками опытного преподавателя.

Объясняю сложное так, чтобы щелкнуло.

🚀 Забрать доступ к Boosty