Тип данных list очень интересный и часто используемый, имеет довольно большое количество методов, которые желательно знать и понимать, как они работают, а в этой статье поговорим о том, как работает метод copy() для list. Методы для list мы рассмотрим здесь, а в этой статье поговорим о копировании листов.
Так вот, есть несколько методов скопировать элементы одного листа в другой, и даже есть метод copy(), который и позволяет нам это сделать:
my_lst = [2, 5, 4, 3, 7] #создадим лист my_lst с элементами new_lst = my_lst.copy() #скопируем элементы с листа my_lst в новый лист new_lst print(new_lst)#распечатаем элементы нашего нового листа new_lst, проверим.
Итак, мы провели копирование элементов с одного листа в другой используя метод copy() для list, и вроде все хорошо и отлично, операция увенчалась успехом! Но, давайте создадим наш исходный список немного по-другому, с вложенным списком:
my_lst = [2, 5, 4, 3, 7, [12, 13, 14]]#Список my_lst с вложенным списком внутри
Методом append() мы можем добавлять элементы в список, а если обратимся по индексу к скопированному списку, т.е. к new_lst, при чем так, что бы получить вложенный список, т.е. в моем примере это индекс 5, так как индексация начинается с 0, и вложенный список имеет индекс 5, и добавим элемент в этот вложенный список:
new_lst[5].append(15) #Обратились к исходному списку по индексу, который соответвует элементу вложенного списка и добавили в него 15 print(new_lst)# выведем элементы скопированного списка, проверим, добавился ли элемент 15
И в результате, мы видим, что он добавился, т.е. вывод будет вот таким:
[2, 5, 4, 3, 7, [12, 13, 14, 15]]
А давайте теперь посмотрим на наш исходный список, не изменился ли он, случайно:
print(my_lst)#вывод в консоль исходного списка
И что мы видим? Он тоже почему-то изменился, хотя мы в него ничего не добавляли и вообще не изменяли его!
Давайте попробуем разобраться, почему же так получилось?
Все просто: элементы в списке хранятся не по значениям, а по ссылкам на эти значения в памяти компьютера, и если первые пять элементов ссылаются на объекты типа int, то шестой элемент ссылается объест типа list, внутри которого тоже есть свои элементы типа int. И, когда мы обращаемся по индексу 5 к этому элементу, мы обращаемся к листу, по ссылке и естественно, мы можем этот лист менять. Метод copy() для list на самом деле копируе только ссылки, а не сами элементы!
Другими словами, представьте себе коробочку, внутри которой лежат игрушки и еще одна коробочка, внутри которой тоже лежат игрушки: мы же можем добавить игрушек во внутреннюю коробочку, или можем их достать от туда, не трогая игрушки основной коробочки! Так и здесь, мы взаимодействуем с списком внутри другого списка, не изменяя внешний список!
Это и есть поверхностное копирование списков!
А как же быть, как произвести копирование, что бы потом можно было изменять скопированный список, работать с ним не изменяя исходный?
Все тоже очень просто, в Python для этого есть так называемое глубокое копирование списка, и мы можем его применить! Для этого необходимо использовать стандартный модуль copy и его метод deepcopy().
import copy #импортируем стандартный модуль my_lst = [2, 5, 4, 3, 7, [12, 13, 14]]# создаем исходный список new_lst = copy.deepcopy(my_lst)# производим копирование с исходного списка в новый, используя модуль copy и его метод deepcopy print(new_lst)# выводим скопированный список, проверяем, произошло ли копирование new_lst[5].append(15)# добавляем элемент в скопированный список print(my_lst)# выводим исходный список и видим, что он не изменился print(new_lst)# выводим новый список и видим, что в него элемент добавился
Итак, мы получили то, что и хотели: наши списки не зависимые друг от друга, это и называется глубоким копированием списков и происходит благодаря реверсивному вхождению метода deepcopy во внутрь вложенного списка и копированию всех его элементов, а метод copy() производит копирование вложенного списка целиком, т.е. просто ссылку на это список.