В КУРСЕ?

Разбираемся в теме

Генератор Python вернул пустой список: куда исчезли уже вычисленные значения?

После знакомства со списками легко ожидать, что любой перебираемый объект можно просматривать снова и снова. Генератор в Python нарушает это ожидание: он выдаёт значения по мере запроса и сохраняет своё положение в вычислении. Поэтому пустой результат повторного обхода часто означает завершённый проход, а не потерю исходных данных.

Список хранит результат, генератор выдаёт следующий элемент

Представим исходные числа 2, 5 и 8. Их квадраты равны 4, 25 и 64. Если заранее собрать эти значения в список, его можно обходить несколько раз. Генераторное выражение g = (x * x for x in [2, 5, 8]) создаёт другой объект. Он позволяет последовательно получать квадраты. Важно различать сами исходные числа, правило преобразования и конкретный генератор, который уже находится на определённом шаге выполнения этого правила.

Первое чтение меняет положение

Вызов next(g) в нашем примере возвращает 4. Теперь первое значение уже выдано. Последующий list(g) собирает оставшиеся результаты и возвращает [25, 64]. Ещё один list(g) даёт пустой список: элементов больше нет. Это последовательные действия над одним и тем же объектом. Если между ними заново выполнить выражение, создающее g, наблюдение получится другим. При разборе ошибки всегда проверяйте, где генератор создан и сколько потребителей успело обратиться к нему.

Диагностика тоже может расходовать данные

Представим, что перед расчётом суммы разработчик выводит list(g), чтобы посмотреть содержимое. Такой просмотр полностью перебирает генератор. После него sum(g) в данном примере вернёт 0, поскольку складывать оставшиеся элементы уже не требуется: их нет. Для сравнения можно сохранить собранный список в отдельной переменной и использовать его повторно. Но тогда программа действительно хранит все полученные значения. Это осознанный выбор организации данных, а не бесплатный способ оставить генератор неизменным.

Выбирать способ повторного использования

Если результаты небольшие и понадобятся несколько раз, список может быть удобнее. Если обработка идёт последовательно и все значения одновременно не нужны, генератор позволяет не собирать полный результат заранее. При этом исходные данные и внутреннее состояние тоже занимают память; обещать её отсутствие нельзя. Для повторного вычисления создают новый генератор, если источник допускает новый проход. Присваивание h = g лишь даёт второе имя прежнему объекту. Генераторная функция с yield также возобновляет выполнение после предыдущей выдачи, а не начинает работу заново при каждом next.

Попробуйте на практике

В отдельном учебном файле или интерактивной сессии проследите один полный проход генератора квадратов. Не меняйте порядок действий во время проверки.

  1. Создайте g выражением (x * x for x in [2, 5, 8]). Сначала запишите предполагаемые результаты следующих действий на бумаге.
  2. Один раз выполните next(g) и сравните возвращённое значение со своим прогнозом.
  3. Выполните list(g), сохраните результат в переменной rest и снова выполните list(g). Объясните различие между двумя списками.
  4. Дважды получите list(rest). Убедитесь, что сохранённый список можно перебрать повторно, не воссоздавая генератор.
  5. Создайте новый генератор тем же выражением и сразу преобразуйте его в список. Сопоставьте полный результат с ранее полученными частями.

Как проверить результат. Ожидаемые результаты по порядку: 4, затем [25, 64], затем []. Повторные обходы rest дают [25, 64], а новый генератор даёт [4, 25, 64]. Если порядок отличается, проверьте повторное создание объекта.

Частые вопросы

Что произойдёт при next(g) после завершения?

Без значения по умолчанию возникнет StopIteration. Цикл for использует этот сигнал для нормального завершения перебора. Это отличается от ошибки в формуле вычисления.

Генератор обязательно работает быстрее списка?

Нет. Скорость зависит от задачи и способа использования. Выбор следует проверять на реальной обработке, учитывая повторные проходы, объём данных и удобство кода.

Самостоятельный разбор темы. Содержание конкретной обучающей программы здесь не представлено.

Зарегистрируйтесь, чтобы уточнить возможность доступа к этому материалу

Зарегистрироваться
← К списку материалов