Ответ
Модуль copy в Python используется для создания копий изменяемых объектов (списков, словарей, пользовательских классов). Прямое присваивание (new_list = old_list) создаёт лишь новую ссылку на тот же объект, а модуль copy позволяет получить отдельный, независимый объект.
Ключевые функции:
copy.copy(x)(Поверхностное копирование): Создаёт новый составной объект, но затем вставляет в него ссылки на объекты, найденные в оригинале. Вложенные изменяемые объекты по-прежнему являются общими.copy.deepcopy(x)(Глубокое копирование): Рекурсивно создаёт новый составной объект, а затем рекурсивно вставляет в него копии объектов, найденных в оригинале. Полностью независимая копия всей иерархии объектов.
Практический пример, демонстрирующий разницу:
import copy
# Исходный список с вложенным списком
original = [1, 2, [3, 4]]
shallow = copy.copy(original) # Поверхностная копия
deep = copy.deepcopy(original) # Глубокая копия
# Изменяем элемент во вложенном списке оригинала
original[2][0] = 'X'
print('Original:', original) # [1, 2, ['X', 4]]
print('Shallow copy:', shallow) # [1, 2, ['X', 4]] -> Изменился!
print('Deep copy:', deep) # [1, 2, [3, 4]] -> Остался неизменным
Когда что использовать:
deepcopy: Когда вам нужна полная, независимая копия структуры данных, и вы планируете изменять вложенные объекты, не затрагивая оригинал. Незаменим для работы с конфигурациями, графами объектов или сложными структурами.copy: Когда объект является одноуровневым (например, список примитивов) или когда вы сознательно хотите, чтобы вложенные объекты оставались общими (для экономии памяти, если они неизменяемы).
Важно: Глубокое копирование может быть ресурсоёмким для очень больших или циклических структур.
Ответ 18+ 🔞
Да ты посмотри, какой народ безмозглый, блядь! Сидят, думают, что new_list = old_list — это копию сделало. Да хуй там плавал, ёпта! Это ж просто новую табличку с названием прилепили к той же самой, блядь, коробке с данными! Поменял в одном месте — везде пиздец, всё поплыло!
А вот модуль copy — это уже, блядь, серьёзные люди придумали. Он как раз для таких распиздяев, которые не хотят нечаянно всё похерить.
Чем там богаты, блядь:
copy.copy(x)(Поверхностная копия): Ну, это как взять новый шкаф, но все ящики из старого тупо переставить в него. Сам шкаф-то новый, а ящики — те же самые, общие. Короче, верхний уровень скопировал, а внутрь заглядывать не стал, ленивая жопа.copy.deepcopy(x)(Глубокая копия): А вот это, сука, перфекционизм! Берёт шкаф, вытряхивает все ящики, а потом каждый ящик, блядь, заново собирает из новых досок! И так до самого низа, пока всё, сука, не склонирует. Полная независимость, мать его.
Смотри сюда, на живом примере, а то не дойдёт:
import copy
# Исходный список, а в нём ещё один список сидит, хитрая жопа
original = [1, 2, [3, 4]]
shallow = copy.copy(original) # Поверхностно скопировали
deep = copy.deepcopy(original) # Глубоко, с чувством, с толком, с расстановкой
# Теперь в оригинале лезем во внутренний список и хуяк — меняем
original[2][0] = 'X'
print('Original:', original) # [1, 2, ['X', 4]] — логично
print('Shallow copy:', shallow) # [1, 2, ['X', 4]] — ОЙ БЛЯДЬ! И тут поменялось! Потому что ящик-то общий!
print('Deep copy:', deep) # [1, 2, [3, 4]] — А тут нихуя! Герой! Отдельная вселенная!
Так когда же что брать, чтоб не обосраться?
deepcopy: Когда тебе нужна, блядь, ТОЧНАЯ и НЕЗАВИСИМАЯ копия всей этой иерархии. Собираешься ковыряться глубоко внутри и не хочешь, чтобы оригинал ахуел от твоих экспериментов. Для конфигов, графов — идеально.copy: Когда объект простой, одноэтажный, или когда вложенные штуки неизменяемые (как кортежи), или когда тебе похуй и ты сознательно хочешь, чтобы они были общими (ну, для экономии памяти там).
И да, deepcopy — он мощный, но если скопировать им структуру, которая сама на себя ссылается, или просто овердохуища большую, то можно и подождать немного. Так что без фанатизма, ёпта.