Почему copy() и deepcopy() – это не одно и то же
Очень частая ситуация: нужно скопировать список или структуру данных.
Пишут так:
import copy
original = [[1, 2], [3, 4]]
# два способа копирования
shallow = original.copy() # поверхностная копия
deep = copy.deepcopy(original) # глубокая копия
# меняем вложенный элемент
shallow[0][0] = 999
print("original:", original)
print("shallow:", shallow)
print("deep:", deep)
Ожидание у многих такое:
• изменится только shallow
• original останется нетронутым
Но реальность другая 👇
original: [[999, 2], [3, 4]] ❗️
shallow: [[999, 2], [3, 4]]
deep: [[1, 2], [3, 4]]
Что произошло?
copy() создаёт новый внешний список, но внутренние объекты остаются теми же.
То есть:
• original и shallow – разные списки
• но их вложенные списки – одни и те же объекты в памяти
Поэтому изменение внутри «протекает» обратно.
В чём разница на уровне идеи
• copy() → копирует только верхний уровень
• deepcopy() → копирует всё рекурсивно
Когда это становится проблемой
Особенно часто это ломает код при работе с:
• вложенными списками (матрицы, таблицы)
• словарями со структурами внутри
• настройками / конфигами
• кэшами
• результатами обработки данных
И самое неприятное – ошибки выглядят «случайными».
Как выбрать правильно
• если структура плоская → можно copy()
• если есть вложенность → почти всегда нужен deepcopy()
• если сомневаешься → лучше явно проверить
Полезный лайфхак
Если хочешь быстро понять, есть ли общие ссылки:
print(original[0] is shallow[0]) # True → один и тот же объект
Главное правило
Если в данных есть вложенные изменяемые объекты – поверхностная копия почти всегда приведёт к багам.
Вывод
Python не копирует «значения», он копирует ссылки на объекты.
И пока это не понимаешь – такие баги неизбежны.