yield, генераторные выражения, протокол итератора (__iter__, __next__) — продвинутый Python, который спрашивают у кандидатов на middle+. Генераторы экономят память при обработке больших данных. На собеседовании просят объяснить ленивое вычисление, написать генератор или показать разницу между списком и генератором.
Вызов `g = gen()` создаёт объект генератора, но не запускает тело функции. Тело начнёт выполняться при `next(g)` или при цикле `for x in g`. Поэтому до начала итерации ничего не печатается.
Подробный разбор →Генератор проходит по `xs` и делает `yield x` только для чётных `x`. Поэтому при входе `[1, 2, 3, 4]` будут отданы 2 и 4. Оборачивание в `list(...)` просто собирает все выданные элементы в список.
Подробный разбор →List comprehension `[row for row in rows]` создаёт весь список сразу и хранит его в памяти. Generator expression `(row for row in rows)` возвращает итератор, который выдаёт элементы по мере запроса, поэтому чаще экономит память на больших данных. Но генератор нельзя «перемотать»: после одного прохода он исчерпывается.
Подробный разбор →После первого `next(it)` единственный элемент 5 уже прочитан. Второй вызов `next(it, -1)` не может получить новое значение, но вместо исключения вернёт значение по умолчанию — -1. Это удобно, когда хотите безопасно попытаться взять элемент без обработки `StopIteration`.
Подробный разбор →При первом `sum(g)` генератор отдаёт 1, 2, 3 и исчерпывается. Второй `sum(g)` суммирует уже пустой iterator, а сумма пустой последовательности в Python — 0. Это типичный баг в аналитике: один и тот же генератор используют для нескольких метрик.
Подробный разбор →В приложении — таймер, прогресс, стрики и 1700+ вопросов по всем темам.
Тренировать Python в Telegram