Поведение переменных в list-comprehension (Python 3)
@python_quizРазберем этот квиз
Коротко: приведённый код напечатает

Почему — разберём пошагово.
Код из задания

- Внутренняя list-comprehension [i for i in range(3)] генерирует список [0, 1, 2].
- Внешняя list-comprehension затем итерируется по этому списку и локально называет переменную i, собирая те же значения в res.
- Важно: в Python 3 переменные, объявленные в list-comprehension, существуют в собственной временной области видимости и не «протекают» (не переопределяют) переменные внешнего окружения.
Поэтому внешняя переменная i, которая была строкой 'outer', остаётся нетронутой, а в res попадает [0, 1, 2].
Демонстрация различий (comprehension vs for-loop)
Чтобы почувствовать разницу, сравним с обычным циклом for, где переменная цикла влияет на внешнюю область видимости:

Здесь переменная i цикла for присваивается в той же области видимости, где была 'outer', поэтому она перезаписывается и в конце становится 2.
Историческая ремарка: поведение в Python 2
В Python 2 list-comprehension «протекали» — переменная цикла оставалась в внешней области видимости. Из-за этого тот же код в Python 2 вёл бы себя иначе и переменная i могла бы стать 2. Это одна из причин, почему в Python 3 поведение изменили — чтобы избежать неожиданных побочных эффектов.
(Пример для понимания поведения в старых версиях; запускать на Python 3 приведённый код так, как указывалось выше, не следует.)
Анализ вариантов ответов (кратко)
- Вариант, соответствующий выводу outer [0, 1, 2]: соответствует поведению Python 3 — переменные comprehension локальны.
- Вариант 2 [0, 1, 2]: описывает ситуацию, когда переменная цикла «утекла» в внешнюю область видимости (поведение, характерное для Python 2 или для обычного for-цикла).
- Вариант outer [0, 1, 2, 2]: не соответствует логике выполнения — ни одна из comprehension-операций не производит лишнего элемента 2.
NameError: name 'i' is not defined — не наступит, потому что внешняя i была определена до comprehension и не была уничтожена.
Выводы и рекомендации
- В Python 3 list-comprehension создают собственную область видимости для переменных цикла — это предохраняет внешний код от непреднамеренного перезаписывания переменных.
- Если вам нужно сохранить значение переменной цикла после итерации (например, последнее значение), используйте явный цикл for.
- Для читаемости кода лучше давать переменным в comprehensions имена, которые не совпадают с названиями переменных во внешней области видимости, чтобы избежать путаницы.
Небольшой чек-лист:
- Нужен доступ к переменной цикла после построения списка? — Используйте for.
- Хочется избежать побочных эффектов? — list-comprehension в Python 3 безопаснее.