Встречается на 40% собеседований по Python

В чем разница между итератором и генератором

Итератор — это объект, который поддерживает протокол итерации и позволяет последовательно перебирать элементы коллекции, а генератор — это функция с оператором yield, которая при вызове возвращает итератор. Другими словами, генератор — это удобный способ создания итератора, но не каждый итератор является генератором.

Как это работает

Итератор в Python — это объект, который реализует методы __iter__() и __next__(). Метод __iter__() возвращает сам итератор, а __next__() возвращает следующий элемент последовательности или выбрасывает исключение StopIteration, когда элементы закончились. Любая коллекция, например список или кортеж, поддерживает итерацию, но сама по себе не является итератором — она возвращает итератор при вызове iter().

Генератор — это функция, содержащая ключевое слово yield. При вызове такая функция не выполняет свой код сразу, а возвращает объект-генератор, который является итератором. Каждый вызов next() выполняет код функции до ближайшего yield, возвращает значение и приостанавливает выполнение. При следующем вызове выполнение продолжается с того места, где остановилось.

Пример

python
# Обычный итератор на основе класса
class Counter:
    def __init__(self, limit):
        self.limit = limit
        self.current = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.limit:
            self.current += 1
            return self.current
        raise StopIteration

# Генератор — функция с yield
def counter_gen(limit):
    current = 0
    while current < limit:
        current += 1
        yield current

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

for num in counter_gen(3):
    print(num)  # 1, 2, 3

Оба подхода дают одинаковый результат, но генератор требует меньше кода и проще для понимания.

Подводные камни

  • Генератор — это одноразовый итератор: после полного перебора он исчерпывается, и повторный for по нему не даст результатов. Обычный итератор тоже может быть одноразовым, но его можно реализовать с возможностью сброса.
  • Генераторы вычисляют значения лениво, то есть по одному за раз. Это экономит память, но если нужно получить все значения сразу, придётся преобразовать генератор в список через list(gen).
  • В генераторе нельзя использовать return с значением — это вызовет исключение StopIteration с этим значением, но обычно return без значения просто завершает генератор.
  • Генераторы не поддерживают индексацию и срезы, так как не хранят все элементы в памяти.

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

Генераторы стоит применять, когда нужно обработать большой поток данных, который не помещается в память целиком, или когда вычисление каждого элемента занимает время и не хочется делать это заранее. Например, чтение файла построчно, бесконечные последовательности или конвейеры обработки данных. Обычные итераторы полезны, когда нужен более сложный контроль над процессом итерации или когда класс уже реализует другие методы, и добавление итерации — лишь часть его поведения.

Коротко

  • Итератор — объект с методами __iter__ и __next__, генератор — функция с yield, возвращающая итератор.
  • Генератор — частный случай итератора, но не наоборот.
  • Генераторы ленивы и экономят память, но одноразовы.
  • Для простых случаев предпочитают генераторы, для сложной логики — явные итераторы.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы