Вопросы по теме «Итераторы и генераторы»

Проверь себя · 1/3разбор после ответа
Создали g = (x for x in [1, 2, 3]), затем s1 = sum(g) и s2 = sum(g). Чему равно s2?

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

Всего в этом разделе 20 вопросов. Каждый — с правильным ответом и кратким разбором теории. Разбито на 4 части по 5 вопросов.

Коллекции и структуры данныхГенераторы списков и встроенные функцииЦиклы и условияИсключения и отладкаРабота с файлами: JSON и CSVФункции и аргументыNumPy: основыPandas и DataFrameСинтаксис и типы данных

Вопросы 15 из 20

1Что создаёт выражение `squares = (x * x for x in xs)`?
AСписок значений типа `list`
BКортеж `tuple` со значениями
CФункцию-генератор, как при `def` с `yield`
DОбъект-генератор с ленивыми значениями
Ответ: Круглые скобки вокруг выражения с `for` создают объект-генератор, а не список и не кортеж.

`(x * x for x in xs)` — это generator expression: он не вычисляет значения сразу, а возвращает объект-генератор, который выдаёт квадраты по одному при `next()` или цикле. Списочное включение использует квадратные скобки, а не круглые. Кортеж так не создаётся: для него нужен литерал `(1, 2, 3)` или вызов `tuple(...)`. Функция-генератор — это конструкция с `def` и `yield`; здесь же нет определения функции, есть только готовый объект-генератор.

Подробный разбор →
2Есть `it = iter(['a', 'b'])`. Что вернёт самый первый вызов `next(it)` сразу после создания итератора?
AПервый элемент `'a'`
BВторой элемент `'b'`
CПустое значение `None`
DИсключение `StopIteration`
Ответ: Свежесозданный итератор всегда стартует с первого элемента последовательности, и первый `next()` возвращает именно его.

`iter(['a', 'b'])` создаёт итератор, указатель которого стоит перед началом. Первый вызов `next(it)` продвигает указатель и возвращает `'a'`. Второй вызов даст `'b'`, а третий — поднимет `StopIteration`, так как элементов больше нет. `next` без значения по умолчанию никогда не возвращает `None` сам по себе: либо отдаёт следующий элемент, либо бросает `StopIteration`.

Подробный разбор →
3Что произойдёт при выполнении `it = iter([])` и затем `next(it)`?
AВернёт значение `None` без ошибок.
BПоднимет исключение `StopIteration`.
CВернёт пустой список `[]` молча.
DПоднимет исключение `IndexError`.
Ответ: `next()` без значения по умолчанию на исчерпанном итераторе всегда поднимает `StopIteration`.

Пустой итератор `iter([])` не имеет элементов, и первый же `next(it)` поднимает `StopIteration` — стандартный сигнал об окончании итерации. `None` вернулся бы только при явном втором аргументе: `next(it, None)`. Пустой список `[]` `next()` возвращать не умеет — он отдаёт элементы, а не контейнеры. `IndexError` относится к индексации списков и в итераторе не возникает.

Подробный разбор →
4Есть функция `def f(x): print(x); return x`. Создали `g = (f(x) for x in [1, 2, 3])`. Сразу после создания `g`, до любой итерации, сколько раз выполнится `print(x)`?
AБудет вызвана `3` раза
BБудет вызвана `1` раз
CБудет вызвана `0` раз
DБудет вызвано исключение
Ответ: Создание генератора не вычисляет элементы: код внутри запускается лишь при итерации.

Выражение `(f(x) for x in [1, 2, 3])` лишь создаёт объект-генератор. Тело генератора — в том числе и вызовы `f(x)` — будет исполняться только при `next(g)` или цикле `for x in g`. До первой итерации функция `f` не вызывается ни разу, поэтому ничего не выводится. Каждое последующее обращение к генератору будет триггерить ровно один вызов `f`.

Подробный разбор →
5Есть `xs = [1, 2, 3]` и `it = iter(xs)`. Сначала выполняется `a = list(it)`, а затем `b = list(it)`. Чему равно `b`?
AПустой список `[]`
BСписок `[1, 2, 3]`
CИсключение `TypeError`
DИсключение `StopIteration`
Ответ: После прохода по итератору он считается исчерпанным: следующее преобразование к списку даст пустой список.

`iter(xs)` создаёт одноразовый итератор: `list(it)` сразу обходит его до конца и собирает все элементы в `a`. После этого внутренний указатель уже стоит «за концом», поэтому повторный `list(it)` ничего не получает и возвращает пустой `[]`. Итератор не «перематывается» автоматически — для нового прохода нужен новый `iter(xs)`. Никакого `TypeError` или необработанного `StopIteration` тут не возникает: `list()` сам корректно обрабатывает конец итерации.

Подробный разбор →
1234

Хотите тренировать интерактивно?

В приложении — таймер, прогресс, стрики и 1700+ вопросов по всем темам.

Тренировать Python в Telegram

Другие темы: Python

Коллекции и структуры данныхГенераторы списков и встроенные функцииЦиклы и условияИсключения и отладкаРабота с файлами: JSON и CSVФункции и аргументыNumPy: основыPandas и DataFrameСинтаксис и типы данных