Python есть ли в примере разница в формировании вложенного списка через генераторы списков и в чем она заключается?
Объясните пожалуйста, почему когда формирую вложенный список через одну строчку:
new_list = [[0]*n for j in range(n)]
То все работает и соответствует заданию (все 1 по диагонали), когда через две строчки вывожу вложенный список, то конечный результат отличается (все 1 во всех элементах)? Хотя промежуточный результат - вложенный список из 0 одинаковый до циклов и в том и другом случае.
1) Вот таким способом:
new_list = [[0]*n for j in range(n)]
print(new_list, type(new_list))
for i in range(n):
new_list[i][i] = 1
for i in new_list:
print(*i)
То в списке n * n (4*4) выводит 0, а по диагонали 1 в соответствии с заданием:
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] <class 'list'>
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
2) До этого попробовал формировать начальный список из 0 через 2 следующие строки вместо одной:
line = [0 for i in range(n)]
new_list = [line for j in line]
То начальный список из 0 формируется такой же, как если через одну строку делать (проверяю через print() сам список и его тип):
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] <class 'list'>
Конечный результат полностью состоит из 1 и не соответствует тому чтобы 1 были только по диагонали, хотя начальный список из 0 вроде бы одинаковый?:
n = int(input())
line = [0 for i in range(n)]
new_list = [line for j in line]
print(new_list, type(new_list))
for i in range(n):
new_list[i][i] = 1
for i in new_list:
print(*i)
Вывод:
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] <class 'list'>
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
Ответы (2 шт):
Тут дело в мутабельности. Проблема в том что line это ссылка и дублируется одна и та же.
Записывая 1 вы записываете её в весь столбец.
Операция умножения создаёт новую ссылку каждый раз и поэтому нет такой проблемы в первом случае.
Можно исправить [list(line) for ....
Объяснение довольно простое - объекты передаются по ссылке. В переменной line у вас получается ссылка на список, которая и копируется много раз. В результате работы второго кода в вашем списке new_list получается n одинаковых ссылок на один и тот же список line. Поэтому первый индекс при обращении к элементу new_list[i][i] можно сказать не учитывается, вы по факту обращаетесь к list[i], таким образом у вас все элементы и становятся равными 1.
new_list = [[0]*n for j in range(n)]
^^^^^ новый список на каждой итерации цикла for
line = [0 for i in range(n)]
new_list = [line for j in line]
^^^^ ссылка на один и тот же список на каждой итерации цикла for