Sobes.tech
Назад к вопросам
Junior — Middle
59

Может ли объект итератора выступать в роли генератора, и наоборот?

Ответ от нейросети

sobes.tech AI

Что хотят услышать интервьюеры:

Итератор и генератор решают похожую задачу — поэтапно отдавать значения, но это не одно и то же. Генератор в Python обычно является итератором, потому что поддерживает __iter__() и __next__(). Обратное неверно: не каждый итератор является генератором, потому что генератор — это более конкретный механизм, создаваемый функцией с yield или генераторным выражением.

Определение:

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

Пример использования:

# Итератор, но не генератор
class Counter:
    def __init__(self, n):
        self.n = n
        self.current = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.current >= self.n:
            raise StopIteration
        value = self.current
        self.current += 1
        return value


# Генератор
def counter_gen(n):
    current = 0
    while current < n:
        yield current
        current += 1


it = Counter(3)
gen = counter_gen(3)

print(next(it))   # 0
print(next(it))   # 1

print(next(gen))  # 0
print(next(gen))  # 1

Пояснение кода:

В примере Counter реализует протокол итератора вручную: объект хранит состояние в полях current и n, а метод __next__() возвращает следующее значение или завершает обход через StopIteration. Это делает объект итератором, но не генератором, потому что yield не используется.

Функция counter_gen — генератор: при каждом yield она приостанавливает выполнение и сохраняет локальное состояние автоматически. При следующем вызове next() выполнение продолжается с того же места.

Шаги работы:

  1. Создаётся объект Counter(3) — это итератор.
  2. Первый next(it) возвращает 0, второй — 1.
  3. Создаётся генератор counter_gen(3).
  4. Первый next(gen) возвращает 0, второй — 1.
  5. Когда значения заканчиваются, оба объекта выбрасывают StopIteration при следующем обращении.

Ключевые моменты:

  • Генератор всегда является итератором.
  • Итератор не обязан быть генератором.
  • Генератор создаётся через yield или генераторное выражение.
  • Итератор обычно реализует __iter__() и __next__() вручную.
  • Если нужен простой ленивый перебор, генератор чаще удобнее и короче.
  • Если нужен полный контроль над состоянием и логикой итерации, можно писать собственный итератор.