Итераторы

Модуль 1: Python Core
11 уровень , 4 лекция
Открыта

5.1 Iterable и Iterator

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

Рассмотрим, как устроены итераторы и как их использовать.

Итерируемый объект (Iterable)

Чтобы по объекту можно было пройтись с помощью цикла for, он должен быть итерируемым – Iterable. Это значит, что наш объект должен реализовать метод __iter__(), который возвращает объект-итератор.

Объект-итератор (Iterator)

Это специальный объект, который имеет функцию __next__() для отдачи следующего элемента последовательности. Когда элементы заканчиваются, метод __next__() вызывает исключение StopIteration как знак прекращения итерации.

Итератор также должен реализовать метод __iter__(), который возвращает сам итератор.

Пример с использованием встроенных функций Python

В этом примере список numbers является итерируемым объектом. Мы получаем итератор с помощью функции iter() и используем функцию next() для перебора элементов до тех пор, пока не будет вызвано исключение StopIteration.


# Итерируемый объект
numbers = [1, 2, 3, 4, 5]
            
# Получаем итератор из итерируемого объекта
iterator = iter(numbers)
            
# Используем итератор для перебора элементов
try:
    while True:
        number = next(iterator)
        print(number)
except StopIteration:
    pass
        

Именно это и происходит, когда вы пишете код типа:


# Итерируемый объект
numbers = [1, 2, 3, 4, 5]
            
for number in numbers:
    print(number)
        

5.2 Суть итератора

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

Шаг 1. Для начала создадим свой класс

Пусть он поочередно возвращает числа от start до end


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        

Шаг 2. Поддержка функции __iter__

Теперь нам нужно добавить ему функцию __iter__, которая будет возвращать объект-итератор, у которого будет вызываться функция __next()__. Мы будем возвращать ссылку на свой же объект – это не запрещено.


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        
    def __iter__(self):
        return self
        

Шаг 3. Поддержка функции __next__

Теперь нужно добавить к нашему-объекту итератору функцию __next__, которая будет возвращать очередной элемент нашего списка. Мы просто будем использовать переменную current:


def __next__(self):
    current = self.current
    self.current += 1
    return current
        

Шаг 4. Остановка итератора

Если итератор вернул уже все значения, которые планировал, он должен кинуть исключение StopIteration. Давайте немного подправим нашу последнюю функцию:


def __next__(self):
    if self.current >= self.end: raise StopIteration
    current = self.current
    self.current += 1
    return current
        

Отлично. Теперь можно пользоваться нашим итератором. Вот пример всего нашего кода:


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:
            raise StopIteration
        current = self.current
        self.current += 1
        return current
        
# Создаем экземпляр пользовательского итератора
my_iter = MyIterator(1, 5)
        
# Используем итератор для перебора элементов
for num in my_iter:
    print(num)

5.3 Правильный итератор

Чем плох итератор из предыдущего примера? Да, это итератор, он рабочий, но он слишком примитивный. С его помощью нельзя идти по одной и той же коллекции элементов одновременно разными итераторами.

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

Пример:


class MyIterable:
    def __init__(self, data):
        self.data = data
    
    def __iter__(self):
        return MyIterator(self.data)
    
class MyIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        item = self.data[self.index]
        self.index += 1
        return item
    
# Использование
my_iterable = MyIterable([1, 2, 3, 4])
for item in my_iterable:
    print(item)
    

В этом примере у нас есть два класса — в первый передается коллекция, по которой мы будем идти итератором. А второй — это и есть итератор, который возвращает элементы коллекции в методе next(). Он тоже довольно простой, но именно так нужно добавлять итераторы в ваши классы.

2
Задача
Модуль 1: Python Core, 11 уровень, 4 лекция
Недоступна
Создание простого итератора
Создание простого итератора
2
Задача
Модуль 1: Python Core, 11 уровень, 4 лекция
Недоступна
Итератор для коллекции
Итератор для коллекции
1
Опрос
Модули и пакеты, 11 уровень, 4 лекция
Недоступен
Модули и пакеты
Модули и пакеты
Комментарии (8)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Tania Solovei Уровень 64
7 октября 2025
Вот что дипсик ответил на эту громадную ересь: Вывод: Твой пример - это как использовать танк для похода в магазин. Технически работает, но на практике: Для простых случаев - используй встроенные итераторы Для средней сложности - используй генераторы (yield) Для сложных кастомных сценариев - тогда да, пиши свои Iterator/Iterable TL;DR: В 99% случаев это излишне, но понимать как это работает - полезно! 🧠
Slevin Уровень 64
7 июля 2025
Следующая лекция: "А теперь рецепт блинчиков!"
Андрей Г Уровень 27
2 июля 2025
Курс "Модули и пакеты". Откуда тут вообще итераторы взялись)
Анастасия Радостная Уровень 24 Expert
17 июня 2025
Уважаемая администрация! Вы бы хотя бы в своем "правильном" решении соблюдали те требования, которые должен выполнить студент в задании. /facepalm/ И такие ситуации вообще в не в первый раз.
Assator Уровень 23
17 февраля 2025
"но именно так нужно добавлять итераторы в ваши классы."? Но в заданиях вы все равно делайте не так.
Mr.Robot Уровень 21 Expert
19 марта 2025
Ну да-да... Более правильно отдавать "отдельный объект", а в задании - "отдать самого себя". Чем тогда "более правильно" - непонятно. Читабельность кода лучше?
Assator Уровень 23
25 марта 2025
Справедливости ради, там написано чем он хуже. Например при использовании вложенного цикла. То есть есил попытаться внутри цикла получить новый итератор ( например чтобы пробежать по списку) то он будет не тот которого от него ожидаешь... Это плохо. Но об это нужно пару раз удариться лбом. Например может дать задание соответствующее...
Simol Sem Уровень 28
9 июня 2025
Assator, спасибо за полезный комментарий