В мире идеальных алгоритмов всё должно работать предсказуемо, но Python решил, что нам не хватает легкой головной боли. Возьмем, к примеру, оператор (repetition), который на бумаге выглядит как благословение для ленивого программиста. Нам обещают «повторение», и если вы работаете с неизменяемыми объектами вроде строк или чисел, то всё пройдет гладко: `'123'3` честно выдаст `'123123123'`, а кортеж `(1, 2)*2` станет `(1, 2, 1, 2)`. Здесь бюрократия кода соблюдается: новый объект создан, старый не пострадал, все довольны. Но стоит нам замахнуться на изменяемые объекты, как начинается тот самый абсурд, который мы так привыкли видеть в учебных программах.
Если вы решите создать список списков через `[[]]*4`, не ждите, что получите четыре независимых пустых контейнера. Вместо этого система услужливо создаст один-единственный объект и размножит четыре ссылки на него. Это как если бы министерство выдало нам одну методичку, но потребовало заполнить её в четырех разных кабинетах одновременно: меняешь что-то в одном — и вуаля, изменения магическим образом просачиваются во все остальные. В памяти компьютера это выглядит как `rep_list = [obj, obj, obj, obj]`, где `obj` — это одна и та же сущность. Стоит вам изменить содержимое по любой из ссылок, как весь ваш «двумерный» список превратится в однородную массу из одинаковых данных.
Для тех, кто всё же хочет, чтобы программа работала по законам логики, а не по законам хаоса, существует list-comprehension. Запись вида `rep_list = [[] for _ in range(4)]` — это единственный способ заставить Python создавать на каждой итерации действительно новый, отдельный объект. Да, внешне они будут выглядеть одинаково пустыми, но при проверке идентификаторов окажется, что это разные объекты, а не одна и та же копия, размноженная по велению оператора повторения. В общем, будьте внимательны к деталям, иначе вместо чистого кода получите ту самую «оптимизацию», которая ломает всё на своем пути.
Источник: kompege ЕГЭ 2027


