← Назад к вопросам

Как написать итератор?

2.0 Middle🔥 171 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как написать итератор?

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

Основной механизм

Для создания итератора нужно:

  1. Определить метод __iter__(), который возвращает сам итератор (обычно self)
  2. Определить метод __next__(), который возвращает следующий элемент
  3. Когда элементы закончились, __next__() должна вызвать исключение StopIteration

Простейший итератор

class CountUp:
    def __init__(self, max):
        self.max = max
        self.current = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current < self.max:
            self.current += 1
            return self.current
        else:
            raise StopIteration

# Использование
counter = CountUp(3)
for num in counter:
    print(num)  # Выведет: 1, 2, 3

Когда вы используете for цикл, Python автоматически:

  1. Вызывает __iter__() для получения итератора
  2. Повторно вызывает __next__() до возникновения StopIteration
  3. Прерывает цикл при StopIteration

Итератор с состоянием

class RangeIterator:
    def __init__(self, start, end, step=1):
        self.current = start
        self.end = end
        self.step = step
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if (self.step > 0 and self.current < self.end) or (self.step < 0 and self.current > self.end):
            value = self.current
            self.current += self.step
            return value
        else:
            raise StopIteration

# Использование
for i in RangeIterator(0, 5):
    print(i)  # 0, 1, 2, 3, 4

for i in RangeIterator(5, 0, -1):
    print(i)  # 5, 4, 3, 2, 1

Итератор по строкам файла

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.rstrip()
        else:
            self.file.close()
            raise StopIteration

# Использование
for line in FileLineIterator(data.txt):
    print(line)

Итератор для матрицы

class MatrixIterator:
    def __init__(self, matrix):
        self.matrix = matrix
        self.row = 0
        self.col = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.row < len(self.matrix):
            value = self.matrix[self.row][self.col]
            
            self.col += 1
            if self.col >= len(self.matrix[self.row]):
                self.col = 0
                self.row += 1
            
            return value
        else:
            raise StopIteration

# Использование
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

for element in MatrixIterator(matrix):
    print(element)  # 1, 2, 3, 4, 5, 6, 7, 8, 9

Итератор с фильтрацией

class FilterIterator:
    def __init__(self, iterable, predicate):
        self.iterable = iter(iterable)  # Получаем итератор из объекта
        self.predicate = predicate
    
    def __iter__(self):
        return self
    
    def __next__(self):
        while True:
            value = next(self.iterable)  # Получаем следующий элемент
            if self.predicate(value):
                return value

# Использование
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_filter = FilterIterator(data, lambda x: x % 2 == 0)
for num in even_filter:
    print(num)  # 2, 4, 6, 8, 10

Итератор с трансформацией (map)

class MapIterator:
    def __init__(self, iterable, func):
        self.iterable = iter(iterable)
        self.func = func
    
    def __iter__(self):
        return self
    
    def __next__(self):
        value = next(self.iterable)  # Может вызвать StopIteration
        return self.func(value)

# Использование
numbers = [1, 2, 3, 4, 5]
squares = MapIterator(numbers, lambda x: x ** 2)
for square in squares:
    print(square)  # 1, 4, 9, 16, 25

Бесконечный итератор

class InfiniteIterator:
    def __init__(self, start=0, step=1):
        self.current = start
        self.step = step
    
    def __iter__(self):
        return self
    
    def __next__(self):
        value = self.current
        self.current += self.step
        return value

# Использование (осторожно! Бесконечный цикл)
for i in InfiniteIterator():
    print(i)
    if i > 5:
        break  # Нужно остановить вручную

Сравнение: Итератор vs Генератор

Генератор — это более простой способ создать итератор:

# Итератор (классический способ)
class CountIterator:
    def __init__(self, max):
        self.max = max
        self.current = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current < self.max:
            self.current += 1
            return self.current
        else:
            raise StopIteration

# Генератор (более простой способ)
def count_generator(max):
    current = 0
    while current < max:
        current += 1
        yield current

# Использование одинаковое
for i in CountIterator(3):
    print(i)

for i in count_generator(3):
    print(i)

Когда использовать собственный итератор

  1. Когда состояние сложное: если нужно отслеживать несколько переменных
  2. Когда нужна инициализация: когда требуется подготовка ресурсов
  3. Когда нужна очистка: когда требуется закрыть файлы или соединения
  4. Когда нужна переиспользуемость: когда итератор вызывается много раз

Лучшие практики

class SafeIterator:
    def __init__(self, data):
        if not hasattr(data, __iter__):
            raise TypeError(f"{type(data)} is not iterable")
        self.data = data
        self.index = 0
    
    def __iter__(self):
        # Возвращаем новый итератор для переиспользования
        return iter(self.data)
    
    def __next__(self):
        if self.index < len(self.data):
            value = self.data[self.index]
            self.index += 1
            return value
        else:
            raise StopIteration

Ключевые моменты

  1. Два метода: __iter__() и __next__()
  2. StopIteration: исключение для завершения итерации
  3. Состояние: итератор должен помнить текущую позицию
  4. Интеграция с for: Python автоматически использует протокол итератора
  5. Генераторы: проще, но итераторы дают больше контроля

Итераторы — фундаментальная часть Python, используемая в циклах, списковых выражениях и многих встроенных функциях (map, filter, zip).

Как написать итератор? | PrepBro