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

В чем разница между итератором и итерируемым объектом?

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

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

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

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

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

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

  • Итерируемый объект (Iterable) — объект, у которого есть метод __iter__(). Он говорит: "Я могу дать тебе итератор".
  • Итератор (Iterator) — объект, у которого есть методы __iter__() и __next__(). Он говорит: "Я умею переходить к следующему элементу".

Зависимость

Iterable ──iter()──> Iterator ──next()──> Element

Каждый итератор является итерируемым (имеет __iter__), но не каждый итерируемый объект — итератор.

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

Определение: объект с методом __iter__(), который возвращает итератор.

class MyIterable:
    def __init__(self, data):
        self.data = data
    
    def __iter__(self):
        """Возвращает итератор"""
        return iter(self.data)  # или MyIterator(self.data)

# Использование
obj = MyIterable([1, 2, 3])
for item in obj:  # for вызовет __iter__
    print(item)

Примеры встроенных итерируемых объектов:

for item in [1, 2, 3]:        # list — итерируемый
    pass

for char in "hello":          # str — итерируемый
    pass

for num in range(5):          # range — итерируемый
    pass

for key in {a: 1, b: 2}:  # dict — итерируемый
    pass

Проверка, является ли объект итерируемым:

from collections.abc import Iterable

print(isinstance([1, 2, 3], Iterable))  # True
print(isinstance("hello", Iterable))    # True
print(isinstance(42, Iterable))         # False

Итератор

Определение: объект с методами __iter__() и __next__(). Вызов __next__() возвращает следующий элемент или вызывает StopIteration.

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):
            result = self.data[self.index]
            self.index += 1
            return result
        else:
            raise StopIteration  # Конец итерации

# Использование
it = MyIterator([1, 2, 3])
print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
print(next(it))  # StopIteration

Примеры встроенных итераторов:

it = iter([1, 2, 3])  # Встроенный итератор
print(next(it))       # 1
print(next(it))       # 2

it = iter("ABC")
print(next(it))       # A

Проверка, является ли объект итератором:

from collections.abc import Iterator

it = iter([1, 2, 3])
print(isinstance(it, Iterator))  # True
print(isinstance([1, 2, 3], Iterator))  # False — это только итерируемый

Визуальное сравнение

# Итерируемый объект — как книга
book = ["chapter1", "chapter2", "chapter3"]
# Итератор — как закладка в книге
reader = iter(book)

while True:
    try:
        chapter = next(reader)  # Закладка переходит на следующую главу
        print(f"Читаю: {chapter}")
    except StopIteration:
        print("Книга прочитана")
        break

Цикл for под капотом

# Эта конструкция
for item in [1, 2, 3]:
    print(item)

# На самом деле работает так:
it = iter([1, 2, 3])  # Вызывает __iter__
while True:
    try:
        item = next(it)  # Вызывает __next__
        print(item)
    except StopIteration:
        break

Практический пример: Пользовательский итератор

Итератор для файла, читающий блоками:

class FileChunkIterator:
    def __init__(self, filename, chunk_size=1024):
        self.filename = filename
        self.chunk_size = chunk_size
        self.file = None
    
    def __iter__(self):
        self.file = open(self.filename, rb)
        return self
    
    def __next__(self):
        chunk = self.file.read(self.chunk_size)
        if chunk:
            return chunk
        else:
            self.file.close()
            raise StopIteration

# Использование
for chunk in FileChunkIterator(large_file.bin, chunk_size=8192):
    process(chunk)  # Обрабатываем по частям, не загружая всё в память

Практический пример: Итерируемый объект

Связанный список с поддержкой итерации:

class LinkedListNode:
    def __init__(self, value):
        self.value = value
        self.next = None

class LinkedList:
    def __init__(self):
        self.head = None
    
    def append(self, value):
        if not self.head:
            self.head = LinkedListNode(value)
        else:
            current = self.head
            while current.next:
                current = current.next
            current.next = LinkedListNode(value)
    
    def __iter__(self):
        """Возвращает итератор"""
        return LinkedListIterator(self.head)

class LinkedListIterator:
    def __init__(self, head):
        self.current = head
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current is None:
            raise StopIteration
        value = self.current.value
        self.current = self.current.next
        return value

# Использование
ll = LinkedList()
ll.append(1)
ll.append(2)
ll.append(3)

for value in ll:  # Итерируемый объект
    print(value)  # 1, 2, 3

Генераторы как итераторы

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

# Вместо создания класса итератора
class RangeIterator:
    def __init__(self, n):
        self.n = n
        self.i = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.i < self.n:
            self.i += 1
            return self.i - 1
        raise StopIteration

# Можно просто написать
def my_range(n):
    i = 0
    while i < n:
        yield i
        i += 1

# Генератор одновременно итерируемый и итератор
gen = my_range(3)
print(next(gen))  # 0
print(next(gen))  # 1

Таблица сравнения

СвойствоИтерируемыйИтератор
__iter__()✅ Есть✅ Есть
__next__()❌ Нет✅ Есть
Возвращает из __iter__()Новый итераторСамого себя (self)
Использование в for✅ Да✅ Да
next()❌ Ошибка✅ Работает
Примерlist, str, dictiter(list), генератор

Итоги

  • Итерируемый объект — это инструмент, например, полка с книгами. На нём есть способ их упорядочить (__iter__).
  • Итератор — это процесс чтения. Он знает, какая книга была последней, и какая будет следующей (__next__).
  • Каждый итератор — итерируемый, но не наоборот.
  • Генераторы — это синтаксический сахар для создания итераторов.
  • Понимание разницы критично для работы с потоками данных, которые нельзя загрузить в память целиком.