Итераторы и итерируемые объекты в ООП: __iter__, __next__
🔄 Итерируемые объекты vs Итераторы: в чём разница?
В Python итерируемый объект (iterable) — это любой объект, который можно «прочитать» поэлементно. Например, списки, строки, словари. Но сам по себе он не умеет «запоминать» текущую позицию при переборе.
А итератор — это «движок» перебора, который знает своё текущее состояние. Он «помнит», на каком элементе остановился.
numbers = [1, 2, 3] # <- iterable (итерируемый объект)
iterator = iter(numbers) # <- iterator (итератор)
print(next(iterator)) # 1
print(next(iterator)) # 2
🏗️ Как устроены итераторы «под капотом»?
Любой итератор в Python реализует два «магических» метода:
__iter__()— возвращает сам объект итератора.__next__()— возвращает следующий элемент или вызываетStopIteration.
class Counter:
def __init__(self, max_num):
self.max_num = max_num
self.current = 0
def __iter__(self):
return self # <- возвращаем сам итератор!
def __next__(self):
if self.current < self.max_num:
self.current += 1
return self.current
raise StopIteration # <- сигнал остановки
counter = Counter(3)
for num in counter: # работает!
print(num) # 1, 2, 3
🔍 Разбираем пример: Итератор для чтения файла
Практичный пример — итератор, который читает файл построчно, не загружая его целиком в память.
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.strip()
self.file.close()
raise StopIteration
# Использование:
for line in FileLineIterator('data.txt'):
print(line) # Читаем файл лениво!
🎯 Главное правило итераторов
Итератор — одноразовый! После перебора его элементы «заканчиваются».
numbers = [1, 2, 3]
iterator = iter(numbers)
print(list(iterator)) # [1, 2, 3]
print(list(iterator)) # [] 😱 Пусто!
🛠️ Как сделать объект итерируемым?
Если нужно, чтобы ваш класс поддерживал цикл for, достаточно реализовать __iter__(), но не обязательно __next__().
class ShoppingCart:
def __init__(self):
self.items = ['яблоко', 'банан', 'апельсин']
def __iter__(self):
return iter(self.items) # делегируем встроенному итератору списка
cart = ShoppingCart()
for item in cart: # работает!
print(item) # яблоко, банан, апельсин
🔥 Продвинутый пример: Бесконечный итератор
Итераторы могут быть бесконечными! Например, генератор случайных чисел.
import random
class RandomNumbers:
def __iter__(self):
return self
def __next__(self):
return random.randint(1, 100)
# Использование:
for num in RandomNumbers():
print(num) # Бесконечный поток чисел!
if num == 42: # Условие выхода
break
🔗 Для углубления в тему рекомендую видео Данилы Бежина: ООП в Python. Там есть разбор итераторов с примерами из реальных проектов.