Что такое протокол итератора в Python?

Ответ

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

  1. Итерируемый объект (Iterable): Любой объект, у которого можно получить итератор. Он должен реализовывать метод __iter__().

    • __iter__(): Возвращает объект-итератор. Примеры итерируемых объектов: списки, строки, словари, файлы.
  2. Итератор (Iterator): Объект, который отслеживает состояние и производит следующее значение в последовательности. Он должен реализовывать два метода:

    • __iter__(): Возвращает сам себя (return self). Это позволяет использовать итераторы там, где ожидаются итерируемые объекты.
    • __next__(): Возвращает следующий элемент. Когда элементы заканчиваются, вызывает исключение StopIteration.

Цикл for неявно использует этот протокол: сначала он вызывает __iter__() у объекта, чтобы получить итератор, а затем многократно вызывает __next__() у этого итератора, пока не будет поймано исключение StopIteration.

Пример реализации своего итератора:

class EvenNumbers:
    """Итератор, который генерирует четные числа до указанного предела."""
    def __init__(self, limit):
        self.limit = limit
        self.current = 0

    def __iter__(self):
        # Возвращает сам объект-итератор
        return self

    def __next__(self):
        if self.current < self.limit:
            value = self.current
            self.current += 2
            return value
        else:
            # Сигнал о завершении итерации
            raise StopIteration

# Использование
print("Использование класса-итератора:")
for number in EvenNumbers(10):
    print(number) # Выведет 0, 2, 4, 6, 8

Более простой способ — генераторы

Функции-генераторы с ключевым словом yield автоматически создают объект, реализующий протокол итератора, что делает код значительно короче и чище.

def even_numbers_generator(limit):
    """Генератор, делающий то же самое, что и класс выше."""
    current = 0
    while current < limit:
        yield current
        current += 2

# Использование генератора
print("nИспользование функции-генератора:")
for number in even_numbers_generator(10):
    print(number) # Выведет 0, 2, 4, 6, 8