Что происходит с этим кодом

Что происходит с этим кодом

@python_quiz

Разберем этот квиз

python

Коротко: это код, который никогда не завершится корректным результатом — итерация по изменяемому списку с добавлением элементов в процессе приведёт к бесконечному росту списка и зависанию (пока программа не будет прервана или не закончится ошибкой из‑за исчерпания памяти).

Почему так происходит — разбор механики

  • list comprehension создаёт итератор по исходному списку nums и последовательно запрашивает следующие элементы по индексу.
  • Внутри comprehension вызывается nums.append(i). Метод append меняет сам список nums и возвращает None.
  • Поскольку итератор смотрит на текущую длину списка при каждой итерации, добавленные элементы становятся частью последовательности итерации — итератор будет «видеть» вновь добавленные элементы и продолжать их обрабатывать.
  • В нашем случае мы добавляем те же значения, которые итерируем, поэтому список будет расти бесконечно: 1 → 1 (добавлен), 2 → 2, 3 → 3, затем вновь добавленный 1 будет итерирован и снова добавлен и т.д.

Дополнительно: метод append возвращает None, поэтому собираемый результат res будет содержать значения None (если бы итерация хотя бы завершилась).

Анализ вариантов вывода (почему они неверны)

  • "[1, 2, 3] [None, None, None]"

Такое поведение означало бы, что список nums не изменился, а comprehension выполнил три вызова append и вернул по три None. Но append изменяет nums, поэтому nums не останется прежним.

  • "[1, 2, 3, 1, 2, 3] [None, None, None]"

Здесь подразумевается, что nums удвоился, а res записал только три значения None. Но если nums удваивается в процессе итерации, итератор продолжит идти дальше и добавит ещё элементы — res тогда тоже будет расти. Получить ровно три None и одновременно модифицированный nums в этом случае нельзя.

  • "[1, 2, 3, 1, 2, 3] [1, 2, 3]"

Этот вариант неверен сразу по двум причинам: append возвращает None, а не добавленное значение, так что res не может быть списком [1,2,3]; и как выше — итерация по добавляемым элементам продолжит выполняться.

  • "Бесконечный цикл или ошибка"

Это именно тот случай: итерация по изменяемому списку с добавлением элементов в процессе приводит к бесконечному увеличению и, фактически, к бесконечному циклу (пока не возникнет внешняя остановка или переполнится память).

Демонстрация безопасного поведения (и что делать правильно)

1) Чтобы получить «удвоение» списка — и избежать бесконечной итерации — итерируйтесь по копии:

python

2) Если вам нужно просто создать новый список на основе существующего — используйте list comprehension без побочных эффектов:

python

3) Если требуется добавить в список все его элементы ещё раз — проще и эффективней использовать extend:

python

4) Показываем, что append возвращает None:

python

Небольшая имитация, чтобы увидеть рост без зависания программы

Если вы хотите «посмотреть» как растёт список при такой ненадёжной конструкции, можно ограничить количество итераций вручную:

python

Этот пример демонстрирует механизм (nums будет расти, res будет содержать None), но не приведёт к бесконечному ожиданию, потому что мы искусственно ограничили количество шагов.

Вывод

Использование list comprehension для побочных эффектов (вызовов, которые меняют итерируемый объект) — крайне плохая практика. В данном примере итерация по изменяемому списку с append приводит к бесконечному добавлению элементов. Всегда либо итерируйтесь по копии, либо применяйте методы, предназначенные для пакетного изменения (extend), либо используйте явные циклы и контролируемую логику.

Report Page