← Маршрут ML-инженерии

Урок · 2 мин чтения · упражнения и самопроверка

Итераторы и генераторы

После урока: объяснить comprehensions и выполнить упражнение «Обработать поток данных без загрузки целиком», обосновав выбранный подход..

Перед началом

Перебор и преобразование

Для обычного прохода коллекции используйте for value in values. Если нужен индекс, enumerate(values) возвращает пары индекс–значение. zip связывает элементы нескольких последовательностей и по умолчанию заканчивается на самой короткой. Если длины должны совпасть, проверьте их или используйте strict=True в подходящей версии Python.

List comprehension создаёт список: [x * x for x in values if x > 0]. Сначала фильтруется элемент, затем вычисляется выражение. Не помещайте в comprehension сложную логику с несколькими побочными эффектами: обычный цикл легче проверить.

Итератор

Итерируемый объект позволяет получить итератор через iter. next берёт следующий элемент, а StopIteration сообщает об окончании. Цикл for выполняет эту обработку за вас. Итератор может быть одноразовым: после исчерпания он не возвращается к началу автоматически.

Генераторная функция использует yield. Выполнение останавливается на очередном значении и продолжается при следующем запросе. Генераторное выражение (x * x for x in values) тоже вычисляет значения по мере запроса. Это полезно для большого потока, когда весь результат сразу не нужен.

Цена ленивости

Генератор экономит память результата, но не устраняет стоимость вычислений и не делает бесконечный источник конечным. Вызов list загрузит весь поток в память. Для повторного прохода создайте новый генератор либо заранее решите, что результат нужно сохранить.

В примере сумма потребляет все три значения. После этого список из того же генератора пуст: новых значений у него больше нет.

Пошаговый пример

python
squares = (x * x for x in range(1, 4))
print(sum(squares))
print(list(squares))

Ожидаемый вывод

text
14
[]

sum потребляет 1, 4, 9. Второй обход того же генератора уже завершён.

Сделайте самостоятельно

Создайте генератор чётных чисел от 0 до n - 1. Посчитайте их сумму без промежуточного списка.

Ответ и критерии проверки

sum(x for x in range(n) if x % 2 == 0). Для n = 6 сумма 0 + 2 + 4 = 6. Для n = 0 результат 0; дополнительный список не создаётся.

Проверьте понимание

1. Можно ли повторно пройти исчерпанный генератор?
2. Как ведёт себя zip по умолчанию при разных длинах?