Доброго времени суток, читатели, зрители моего канала programmer's notes. Не забывайте подписываться и писать свои комментарии к моим статьям и видео.
Вложенные коллекции и их копирование с помощью модуля copy
Посмотрел на основной курс по Python'у и вдруг понял, что темы вложенности коллекций я как-то почти и не коснулся. Ну разве что здесь. Поэтому перед вами статья как по основному курсу Python, так и по курсу стандартных библиотек.
Вспоминая азы Python
Начну с известных для вас вещей
ls = [1, 3, 5, 8]
lss = ls
Что означает этот фрагмент? Теперь и ls и lss указывают на один и тот же объект [1, 3, 5, 8]. lss не новый список (объект), а указатель на уже существующий. Помните это, иначе ошибок вам не избежать.
Для копирования списка будет правильно написать
lss = ls[:]
Теперь мы получаем два разных списка ls и lss.
Есть также метод copy(), о котором мы говорили здесь.
И вот тут есть один важный момент. Что если элементами списка (или другой коллекции) являются сложные объекты, т.е. другие коллекции. Рассмотрим пример
#!/usr/bin/python3
ls = [1, [3, 5], 8]
lss = ls[:]
ls[0] = 6
print(ls)
print(lss)
ls[1][0] = 33
print(ls)
print(lss)
Результат выполнения программы
[6, [3, 5], 8]
[1, [3, 5], 8]
[6, [33, 5], 8]
[1, [33, 5], 8]
Вот уже интересно стало. Скопировалось всё, но простые элементы скопировались полностью, а вложенный список не скопировался, скопировался только его указатель. В результате, если мы будем менять содержимое вложенного списка, то изменения произойдёт и в ls и lss. Вот этот факт может стать источником трудно понимаемой ошибкой для начинающих программистов.
Копирование объектов с помощью модуля copy
Ну а теперь перейдём к новому для нас модулю, который называется copy. Его можно использовать для копирования коллекций. Давайте сразу перейдём к примерам.
Пример 1. Поверхностное копирование, аналогичное lss = ls[:].
#!/usr/bin/python3
import copy
ls = [1, [3, 5], 8]
lss = copy.copy(ls)
ls[0] = 6
print(ls)
print(lss)
ls[1][0] = 33
print(ls)
print(lss)
Результат выполнения программы
[6, [3, 5], 8]
[1, [3, 5], 8]
[6, [33, 5], 8]
[1, [33, 5], 8]
Здесь мы видим знакомую уже нам картину.
Замечание. Только не путайте метод copy() модуля copy и метод copy() объекта список.
Пример 2. Глубокое копирование с помощью метода deepcopy()
#!/usr/bin/python3
import copy
ls = [1, [3, 5], 8]
lss = copy.deepcopy(ls)
ls[0] = 6
print(ls)
print(lss)
ls[1][0] = 33
print(ls)
print(lss)
Результат выполнения программы
[6, [3, 5], 8]
[1, [3, 5], 8]
[6, [33, 5], 8]
[1, [3, 5], 8]
Теперь чётко видно, что список lss стал абсолютно независимом от изначального списка. Метод deepcopy() будет правильно работать, если глубина вложенности будет более двух. Если хотите - проверьте.
Ну вот пока всё. Пишите свои предложения и замечания и занимайтесь программированием, хотя бы для поддержания уровня интеллекта.