Магические методы __iter__ и __next__

В этом уроке мы рассмотрим основные понятия, связанные с итерацией в Python: итерация, итерируемый объект, и итератор.


Итерация

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

Простой способ реализации итерации — использование циклов, таких как for и while. Например, код ниже выводит сообщение "Привет, мир!" пять раз:

for i in range(5):
    print("Привет, мир!")

Также этот код можно переписать с помощью цикла while:

times = 0

while times < 5:
    print("Привет, мир!")
    times += 1

И в том, и в другом случае мы имеем дело с итерацией.


Итерируемый объект и итератор

Итерируемый объект — это объект, который можно обходить с помощью цикла for. Например, любые коллекции (строки, списки, кортежи, множества) поддерживают итерацию, и элементы таких коллекций можно перебрать в цикле.

Однако, если мы попытаемся проитерироваться по экземпляру нашего класса без реализации необходимых методов, мы получим ошибку:

TypeError: 'Student' object is not iterable

Итератор — это объект, который возвращает следующий элемент последовательности или выбрасывает исключение StopIteration, если элементов больше нет. Итератор должен поддерживать встроенную функцию next().


Встроенная функция iter()

Встроенная функция iter() работает следующим образом:

  1. Проверяет наличие магического метода __iter__ у объекта. Если метод существует, он вызывается, и результат должен быть итератором.
  2. Если метод __iter__ отсутствует, проверяет наличие метода __getitem__. Если метод присутствует, Python создаст итератор, который будет извлекать элементы объекта по порядку.
  3. Если оба метода не реализованы, возникает исключение TypeError.

Например, у строк, списков и кортежей уже реализована поддержка функции iter(), что позволяет получать итераторы.

Числа и логические значения по умолчанию не поддерживают итерацию.


Создание итерируемого объекта

Чтобы ваш класс мог использоваться в качестве итерируемого объекта, необходимо реализовать магический метод __iter__ и вернуть итератор. Пример:

class Student:
    def __init__(self, name, surname):
        self.name = name
        self.surname = surname

    def __iter__(self):
        return iter(self.surname)

В этом примере метод __iter__ возвращает итератор строки, которая является коллекцией. Также можно реализовать метод __getitem__, чтобы сделать объект итерируемым.


Создание итератора

Чтобы объект стал итератором, необходимо реализовать два метода:

  • __next__, который определяет порядок выдачи элементов и выбрасывает StopIteration, когда элементы закончились.
  • __iter__, который возвращает сам объект.

Пример реализации итератора внутри класса:

class Student:
    def __init__(self, name, surname):
        self.name = name
        self.surname = surname
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index < len(self.surname):
            letter = self.surname[self.index]
            self.index += 1
            return letter
        raise StopIteration

Теперь мы можем использовать объект Student как итератор:

ivan = Student('Ivan', 'Sidorov')
for letter in ivan:
    print(letter)


Итератор через отдельный класс

Итератор также можно реализовать в отдельном классе:

class Counter:
    def __init__(self, low, high):
        self.current = low - 1
        self.high = high

    def __iter__(self):
        return IteratorCounter(self)

class IteratorCounter:
    def __init__(self, counter):
        self.counter = counter

    def __iter__(self):
        return self

    def __next__(self):
        self.counter.current += 1
        if self.counter.current <= self.counter.high:
            return self.counter.current
        raise StopIteration

В этом примере класс Counter является итерируемым объектом, а класс IteratorCounter — итератором.


Сравнение итератора и итерируемого объекта

Итерируемый объект:

  • Имеет метод __iter__, возвращающий итератор.
  • Можем использовать много раз.
  • Хранит данные о состоянии итерации.

Итератор:

  • Реализует методы __iter__ и __next__.
  • Можно использовать один раз.
  • Не хранит данные, а выдает их по одному элементу за раз.

Вот таблица, сравнивающая итерируемые объекты и итераторы:

ВозможностиИтерируемые объектыИтераторы
Поддерживают работу с функцией iter()
Поддерживают работу с функцией next()
Можно использовать в цикле for напрямую
Можно итерироваться много раз
Хранят информацию о состоянии итерации
Эффективное использование памяти

 

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

Перейти к следующему шагу

Комментарии