Может ли объект итератора выступать в роли генератора, и наоборот?
Ответ от нейросети
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() выполнение продолжается с того же места.
Шаги работы:
- Создаётся объект
Counter(3)— это итератор. - Первый
next(it)возвращает0, второй —1. - Создаётся генератор
counter_gen(3). - Первый
next(gen)возвращает0, второй —1. - Когда значения заканчиваются, оба объекта выбрасывают
StopIterationпри следующем обращении.
Ключевые моменты:
- Генератор всегда является итератором.
- Итератор не обязан быть генератором.
- Генератор создаётся через
yieldили генераторное выражение. - Итератор обычно реализует
__iter__()и__next__()вручную. - Если нужен простой ленивый перебор, генератор чаще удобнее и короче.
- Если нужен полный контроль над состоянием и логикой итерации, можно писать собственный итератор.