Генератор-итератор: почему list возвращает [1, 2]
@python_quizРазберем этот квиз
Код из задания:

Краткий результат: программа выведет [1, 2]. Дальше объясню почему и разберу все варианты.
Понимание ключевых понятий
- (i for i in range(3)) — это генераторное выражение. Оно не создаёт список, а возвращает объект-генератор (он же итератор).
- Генератор-итератор — это одноразовый (single-pass) итератор: при вызове next() он продвигает своё внутреннее состояние и "потреблённые" значения уже не вернутся.
- Присваивание
it2 = it1не создаёт копию последовательности, а просто создаёт ещё одну ссылку на тот же объект-генератор.
Пошаговая эмуляция кода
- it1 = (i for i in range(3)) — создаём генератор, внутренняя очередь значений: 0, 1, 2.
it2 = it1— it1 и it2 указывают на один и тот же генератор.- next(it1) — запрашиваем первый элемент генератора; он возвращает 0 и перемещает внутренний указатель на следующий элемент.
- list(it2) — преобразует оставшийся итератор (тот же объект) в список. Генератор уже "съел" 0, поэтому остаются 1 и 2. Результат: [1, 2].
Демонстрация в коде

Последний print показывает пустой список, потому что генератор уже полностью итерирован.
Разбор вариантов (логика, почему другие ответы неверны)
- [0, 1, 2] — этот вариант соответствовал бы ситуации, если бы list брался до вызова next, или если бы it2 был независимым итератором, например, созданным заново. Но тут next уже съел 0, так что полный список не вернётся.
- [1, 2] — соответствует описанному поведению: первый элемент был потреблён вызовом next, оставшиеся элементы возвращаются list.
- [0, 1] — такой результат невозможен в данном коде: чтобы получить [0, 1], нужно было бы, например, взять первые два элемента, но list(it2) берёт всё, что осталось (включая 2).
- [] — пустой список получился бы только если генератор к моменту вызова list уже был полностью итерирован (например, если до этого вызвать next три раза или уже где-то пройтись по генератору полностью).
Как получить независимые итераторы
Если вам нужны два независимых источника значений, используйте:
- последовательности (list, tuple), которые можно итерировать сколько угодно раз;
- отдельные генераторы (создавайте новое генераторное выражение для каждого итератора);
- itertools.tee для клонирования итератора (с оговорками по памяти):
Примеры:

Выводы и практические советы
- Генераторы — удобны и экономят память, но они одноразовые. После прохождения их нельзя "перемотать" назад.
- Присвоение переменной другой переменной не создаёт копию итератора — это просто ещё одна ссылка на тот же объект.
- Если нужно многократно итерировать данные, либо сохраните их в контейнер (list/tuple), либо создавайте новый генератор каждый раз, либо используйте tee, учитывая затраты памяти.
Небольшой чеклист:
- Хотите ленивую одноразовую обработку → используйте генератор.
- Хотите многократные проходы → используйте список/кортеж или создавайте новые генераторы.