Почему при изменении одного элемента в списке, созданном через умножение, меняются все остальные?
Создал список так: matrix = [[0] * 3] * 3 matrix[0][1] = 5 print(matrix) # Выводит [[0, 5, 0], [0, 5, 0], [0, 5, 0]] — почему изменились все строки? Ожидал увидеть [[0, 5, 0], [0, 0, 0], [0, 0, 0]], но изменился второй элемент в каждой строке. Почему оператор * ведёт себя так странно с вложенными списками? Как правильно создать независимые строки матрицы? Ведь если я создаю простой список [0] * 5, то изменения работают корректно.
1 ответ
классика) * не копирует внутренний список — он копирует ссылку на него. то есть [[0]*3]*3 создаёт не три разные строки, а три имени для ОДНОГО и того же списка [0, 0, 0]. меняешь элемент через любую строку — меняется единственный реальный список, поэтому «поменялось во всех».
проверить легко:
matrix = [[0]*3]*3
print(matrix[0] is matrix[1]) # True — это один и тот же объект
а [0]*5 ведёт себя нормально, потому что там копируются числа, а числа неизменяемы: элемент можно только заменить целиком, соседей это не заденет. проблема именно с вложенными изменяемыми объектами — списками, словарями.
как правильно — собирать через генератор, чтобы каждая строка создавалась заново:
matrix = [[0]*3 for _ in range(3)]
matrix[0][1] = 5
print(matrix) # [[0, 5, 0], [0, 0, 0], [0, 0, 0]]
тут [0]*3 внутри — ок, потому что 0 неизменяем. а внешний список собираем через for, и каждая строка получается своим отдельным объектом