Чем итератор отличается от итерируемого объекта?
- Что такое протокол итератора?
- Как работает цикл for под капотом?
- Что такое __iter__ и __next__?
Итерируемый объект умеет выдать итератор (__iter__), итератор выдаёт значения по одному (__next__).
forвызываетiter(obj), затемnext()доStopIteration- Список итерируемый, но не итератор: его можно обходить много раз
А ещё Итератор одноразовый, его __iter__ возвращает сам себя
Подробно
Итерируемый объект (iterable) — всё, что можно обойти в for: список, строка, словарь, файл, range. У него есть метод __iter__, который возвращает новый итератор. (Старый вариант — __getitem__ с индексами от 0 — тоже поддерживается.)
Итератор — объект с текущей позицией. Его __next__ возвращает следующий элемент или бросает StopIteration, когда элементы кончились. Его __iter__ возвращает self, поэтому итератор тоже можно передать в for.
Цикл for x in obj разворачивается так:
it = iter(obj);- в цикле
x = next(it); - при
StopIteration— выход.
Следствия: список можно обходить сколько угодно раз — каждый for получает новый итератор. Итератор (и генератор) исчерпывается за один проход.
Свой итерируемый класс проще всего сделать, написав __iter__ как генератор.
Пример
nums = [1, 2]
it = iter(nums)
next(it), next(it) # (1, 2)
next(it) # StopIteration
class Countdown:
def __init__(self, start):
self.start = start
def __iter__(self): # каждый for — новый генератор
n = self.start
while n > 0:
yield n
n -= 1
list(Countdown(3)) # [3, 2, 1]
list(Countdown(3)) # [3, 2, 1] — можно сноваЧто хотят услышать
- Чёткое разделение двух понятий и их методов.
- Как работает
forчерезiterиnext. - Одноразовость итератора и многоразовость коллекции.
Частые ошибки
- Называть список итератором.
- Делать класс, который является сам себе итератором, и удивляться, что второй проход пустой.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✓Итерируемый объект выдаёт итератор (__iter__), итератор отдаёт значения через __next__ и одноразовый
- ✗Список сам является итератором с __next__, поэтому после одного обхода в for его нельзя обойти повторно
- ✗for вызывает __next__ у итерируемого объекта напрямую, без iter()
- ✗Итератор можно перезапустить с начала вызовом iter()
Что спросят дальше
Разбор темы
- Итераторы, генераторы и itertools
Протокол итерации, генераторы и генераторные выражения, срезы, send и yield from, ленивые инструменты itertools.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.