← Назад к курсу

Итераторы в Python: подробное объяснение

Итераторы в Python: подробное объяснение

Что такое итератор?

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

  • __iter__() - возвращает сам итератор
  • __next__() - возвращает следующий элемент

Базовый пример создания итератора

class SimpleIterator:
    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 += 1
            return value
        else:
            raise StopIteration

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

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

Важно различать:

  • Итерируемый объект - объект, который можно использовать в цикле for
  • Итератор - объект, который фактически производит итерацию
# Итерируемый объект (но не итератор)
my_list = [1, 2, 3]
iter_obj = iter(my_list)  # получаем итератор из итерируемого объекта

print(next(iter_obj))  # 1
print(next(iter_obj))  # 2
print(next(iter_obj))  # 3
# print(next(iter_obj))  # StopIteration

Встроенные итераторы и итерируемые объекты

Python имеет множество встроенных итерируемых типов:

  • Списки, кортежи, строки
  • Словари, множества
  • Файлы
  • Функции range(), enumerate(), zip(), map(), filter()
# Примеры использования
# 1. Файлы как итераторы
with open('file.txt') as f:
    for line in f:  # файл - итератор строк
        print(line)

# 2. enumerate() возвращает итератор пар (индекс, значение)
for i, value in enumerate(['a', 'b', 'c']):
    print(f"Index: {i}, Value: {value}")

# 3. zip() объединяет несколько итераторов
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
for name, age in zip(names, ages):
    print(f"{name} is {age} years old")

Генераторы как частный случай итераторов

Генераторы - это специальный тип итераторов, создаваемых с помощью функций с yield или генераторных выражений.

Функции-генераторы

def count_down(n):
    while n > 0:
        yield n
        n -= 1

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

Генераторные выражения

# Аналогично list comprehension, но создает генератор
squares = (x**2 for x in range(10))
print(next(squares))  # 0
print(next(squares))  # 1
# ...

# Экономит память - не хранит все элементы сразу

Кастомные итераторы с состоянием

Итераторы могут иметь сложное внутреннее состояние:

class FibonacciIterator:
    def __init__(self, max_count):
        self.max_count = max_count
        self.count = 0
        self.a, self.b = 0, 1
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.count >= self.max_count:
            raise StopIteration
        
        if self.count == 0:
            result = self.a
        elif self.count == 1:
            result = self.b
        else:
            result = self.a + self.b
            self.a, self.b = self.b, result
        
        self.count += 1
        return result

# Генерация первых 10 чисел Фибоначчи
fib_iter = FibonacciIterator(10)
print(list(fib_iter))  # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

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

import itertools

# 1. Бесконечный счетчик
counter = itertools.count(start=10, step=2)
print(next(counter))  # 10
print(next(counter))  # 12
# ... и так до бесконечности

# 2. Циклический итератор
cycle_iter = itertools.cycle(['A', 'B', 'C'])
print(next(cycle_iter))  # A
print(next(cycle_iter))  # B
print(next(cycle_iter))  # C
print(next(cycle_iter))  # A (снова)

# 3. Повторение элемента
repeater = itertools.repeat('Hello', 3)  # только 3 раза
print(list(repeater))  # ['Hello', 'Hello', 'Hello']

Практические применения итераторов

1. Ленивые вычисления

def read_large_file(filename):
    """Чтение большого файла без загрузки в память целиком"""
    with open(filename) as f:
        for line in f:
            yield line.strip()

# Обработка файла построчно
for line in read_large_file('huge_file.txt'):
    process_line(line)

2. Конвейерная обработка данных

def pipeline(data):
    """Конвейер обработки данных"""
    # Каждый шаг - генератор
    step1 = (x * 2 for x in data)
    step2 = (x + 10 for x in step1)
    step3 = (x for x in step2 if x % 3 == 0)
    return step3

result = pipeline(range(100))
print(list(result))  # Все вычисления ленивые

3. Собственные коллекции

class TreeNode:
    def __init__(self, value):
        self.value = value
        self.children = []
    
    def add_child(self, child):
        self.children.append(child)
    
    def __iter__(self):
        """Итерация по значениям в дереве (обход в глубину)"""
        yield self.value
        for child in self.children:
            yield from child

# Создание дерева
root = TreeNode(1)
child1 = TreeNode(2)
child2 = TreeNode(3)
root.add_child(child1)
root.add_child(child2)

print(list(root))  # [1, 2, 3]

Полезные функции для работы с итераторами

import itertools

# 1. Цепочка итераторов
chain_iter = itertools.chain([1, 2], 'ab', (4, 5))
print(list(chain_iter))  # [1, 2, 'a', 'b', 4, 5]

# 2. Срезы итераторов
slice_iter = itertools.islice(range(100), 10, 20, 2)
print(list(slice_iter))  # [10, 12, 14, 16, 18]

# 3. Группировка
data = sorted(['apple', 'banana', 'cherry', 'date'], key=len)
for key, group in itertools.groupby(data, key=len):
    print(f"Length {key}: {list(group)}")

# 4. Комбинации
print(list(itertools.combinations('ABC', 2)))  # [('A', 'B'), ('A', 'C'), ('B', 'C')]
print(list(itertools.permutations('AB', 2)))   # [('A', 'B'), ('B', 'A')]

Особенности и ограничения

  1. Одноразовость: большинство итераторов можно пройти только один раз

    numbers = iter([1, 2, 3])
    list(numbers)  # [1, 2, 3]
    list(numbers)  # [] - итератор исчерпан
    
  2. Ленивые вычисления: элементы вычисляются по мере необходимости

  3. Экономия памяти: не требуют хранения всех данных одновременно

  4. Не поддерживают индексацию: нельзя получить элемент по индексу как в списке

Полезные паттерны

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

class CheckpointIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0
        self.checkpoints = []
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        value = self.data[self.index]
        self.index += 1
        return value
    
    def checkpoint(self):
        self.checkpoints.append(self.index)
    
    def restore(self, checkpoint_idx=-1):
        if checkpoint_idx < len(self.checkpoints):
            self.index = self.checkpoints[checkpoint_idx]

Заключение

Итераторы в Python - мощный инструмент для:

  • Эффективной работы с данными (экономия памяти)
  • Ленивых вычислений
  • Создания конвейеров обработки
  • Работы с бесконечными или большими последовательностями

Они являются фундаментальной частью Python и лежат в основе многих встроенных конструкций языка, включая циклы for и генераторные выражения.

Дополнительный материал

Вопросы учеников к ИИ-помощнику и ответы по теме урока

Вопрос: alexis@ts-group.ru · 2025-12-23 12:42
расскажи про функцию reversed()
Ответ ИИ:

Привет! Функция reversed() в Python возвращает итератор, который позволяет перебирать последовательность в обратном порядке. Она не изменяет исходную последовательность, а создает новый итератор для обратного обхода.

Вот ключевые моменты:

  • Назначение: Создает итератор для обратного обхода итерируемого объекта (строки, кортежа, списка и т.д.).
  • Синтаксис: reversed(sequence)
  • Возвращаемое значение: Итератор, выдающий элементы последовательности в обратном порядке.
  • Пример:

    python my_string = "hello" reversed_string = reversed(my_string) for char in reversed_string: print(char) # Выведет: o, l, l, e, h

    python my_list = [1, 2, 3, 4, 5] reversed_list = reversed(my_list) print(list(reversed_list)) # Выведет: [5, 4, 3, 2, 1]

Упражнение:

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

Вопрос: alexis@ts-group.ru · 2025-12-23 12:43
какие еще функции встроенные это итераторы?
Ответ ИИ:

Привет! Помимо reversed(), в Python есть несколько других встроенных функций, которые возвращают итераторы, позволяя эффективно работать с данными. Они особенно полезны, когда нужно обрабатывать большие объемы информации, не загружая их все в память сразу.

Вот некоторые из них:

  • range(): Создает последовательность чисел.

    • range(stop): от 0 до stop (не включая stop).
    • range(start, stop): от start до stop (не включая stop).
    • range(start, stop, step): от start до stop с шагом step.
    • Пример: for i in range(5): print(i) (выведет 0, 1, 2, 3, 4)
  • enumerate(): Добавляет счетчик к итерируемому объекту и возвращает итератор кортежей (индекс, элемент).

    • Пример: for i, char in enumerate("abc"): print(f"Index: {i}, Char: {char}") (выведет Index: 0, Char: a, Index: 1, Char: b, Index: 2, Char: c)
  • zip(): Объединяет несколько итерируемых объектов в один итератор кортежей.

    • Пример: names = ['a', 'b']; ages = [1, 2]; for name, age in zip(names, ages): print(f"{name} is {age}") (выведет a is 1, b is 2)
  • map(): Применяет функцию к каждому элементу итерируемого объекта и возвращает итератор результатов.

    • Пример: numbers = [1, 2, 3]; squared = map(lambda x: x**2, numbers); print(list(squared)) (выведет [1, 4, 9])
  • filter(): Фильтрует элементы итерируемого объекта на основе заданной функции и возвращает итератор отфильтрованных элементов.

    • Пример: numbers = [1, 2, 3, 4, 5]; even = filter(lambda x: x % 2 == 0, numbers); print(list(even)) (выведет [2, 4])

Упражнение:

Используя функцию zip(), создайте функцию, которая принимает два списка (имена и фамилии) и возвращает список строк, содержащих полное имя (имя + пробел + фамилия).