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

Чем отличается итератор от генератора?

1.3 Junior🔥 221 комментариев
#Python Core

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

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

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

# Итератор vs Генератор

Это часто путают, но это разные концепции. Генератор — это частный случай итератора, созданный функцией.

Определения

Итератор:

  • Объект класса, который реализует методы iter() и next()
  • Может содержать состояние и логику в методах
  • Создаётся явно через class
  • Более гибкий и контролируемый

Генератор:

  • Функция, содержащая ключевое слово yield
  • Возвращает объект генератора (который является итератором)
  • Более компактный и читаемый
  • Автоматически реализует iter() и next()

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

# 1. ИТЕРАТОР (через класс)
class CountUpIterator:
    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

iter_obj = CountUpIterator(3)
for num in iter_obj:
    print(num)  # 1, 2, 3

# 2. ГЕНЕРАТОР (функция с yield)
def count_up_generator(max):
    current = 0
    while current < max:
        current += 1
        yield current

gen_obj = count_up_generator(3)
for num in gen_obj:
    print(num)  # 1, 2, 3

# Оба дают одинаковый результат, но генератор просще!

Ключевые различия

АспектИтераторГенератор
ОпределениеКласс с iter/nextФункция с yield
КодМногострочный, explicitКомпактный, implicit
СостояниеХранится в self.*Хранится автоматически
КонтрольПолный контрольМеньше контроля
ПамятьХранит всё состояниеЛениво вычисляет
Легко читатьМеньшеБольше

Генератор — это итератор!

def my_generator():
    yield 1
    yield 2
    yield 3

gen = my_generator()

# Генератор имеет методы __iter__ и __next__
print(hasattr(gen, '__iter__'))   # True
print(hasattr(gen, '__next__'))   # True

# Можно вызвать явно
print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3

try:
    next(gen)
except StopIteration:
    print("Генератор исчерпан")

Когда использовать

Используй генератор когда:

  • Нужна простая последовательность значений
  • Логика простая (< 20 строк)
  • Нужна ленивое вычисление (экономия памяти)
  • Читаемость важна
# Чтение большого файла построчно
def read_large_file(file_path):
    with open(file_path) as f:
        for line in f:
            yield line.strip()

for line in read_large_file('huge.txt'):
    process(line)  # обрабатываем построчно, не загружая в память

Используй итератор когда:

  • Нужна сложная логика
  • Нужны доп. методы и свойства
  • Состояние сложное (несколько переменных)
  • Нужна гибкость
# Сложный итератор с дополнительным функционалом
class WindowIterator:
    def __init__(self, data, window_size):
        self.data = data
        self.window_size = window_size
        self.index = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index + self.window_size > len(self.data):
            raise StopIteration
        
        window = self.data[self.index:self.index + self.window_size]
        self.index += 1
        return window
    
    def reset(self):
        self.index = 0

w = WindowIterator([1, 2, 3, 4, 5], 3)
for window in w:
    print(window)  # [1,2,3], [2,3,4], [3,4,5]

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

# Генератор может быть бесконечным
def infinite_numbers():
    n = 0
    while True:
        yield n
        n += 1

gen = infinite_numbers()
print(next(gen))  # 0
print(next(gen))  # 1
print(next(gen))  # 2
# Может работать бесконечно

# Практическое применение
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

fib = fibonacci()
for _ in range(5):
    print(next(fib))  # 0, 1, 1, 2, 3

Generator Expression (выражение-генератор)

# Похоже на list comprehension, но экономит память
squares_list = [x**2 for x in range(1000000)]  # память: ~40MB
squares_gen = (x**2 for x in range(1000000))   # память: ~几KB

print(next(squares_gen))  # 0
print(next(squares_gen))  # 1
print(next(squares_gen))  # 4

Важные моменты

  1. Генератор можно использовать только один раз
  2. После StopIteration объект "мёртв" — нужно создать новый
  3. Генератор более читаем, итератор более гибкий
  4. Оба следуют протоколу итератора
  5. Большинство встроенных функций ожидают итераторы

Вывод: генератор — это просто удобный способ создать итератор функцией вместо класса.

Чем отличается итератор от генератора? | PrepBro