← Назад к списку
ТехническаяPythonJunior

Чем отличается поверхностное копирование от глубокого? Когда какое использовать?

Короткий ответ

  • Присваивание копию не создаёт — только новую ссылку
  • copy.copy() копирует верхний уровень, вложенные объекты общие
  • copy.deepcopy() рекурсивно копирует всю структуру
  • Срез list[:] и dict.copy() — поверхностные копии
  • deepcopy дороже и справляется с циклическими ссылками
  • Для плоских структур достаточно shallow-копии

Поверхностная копия дублирует только верхний контейнер и делит вложенные объекты с оригиналом, глубокая — рекурсивно копирует всё.

Как сказать вслух

пример ответа

Сначала важно, что присваивание вообще ничего не копирует — обе переменные указывают на один объект. Поверхностная копия создаёт новый контейнер, но вложенные объекты остаются общими: изменил вложенный список в копии — изменился и оригинал. Глубокая копия рекурсивно дублирует всю структуру, поэтому объекты полностью независимы, но это дороже. Для плоского списка чисел хватит среза, для вложенных структур нужен deepcopy.

Подробный ответ

Основной ответ

Присваивание b = a создаёт вторую ссылку на тот же объект. Поверхностная копия (copy.copy(), list(a), a[:], dict.copy()) создаёт новый контейнер того же типа, но элементы — те же самые объекты: для неизменяемых элементов это безопасно, для вложенных списков и словарей изменения «просвечивают» в оригинал. Глубокая копия (copy.deepcopy()) рекурсивно копирует все уровни, отслеживая уже скопированные объекты через memo-словарь — поэтому корректно обрабатывает циклические ссылки, но заметно дороже по времени и памяти. Классы могут управлять копированием через __copy__ и __deepcopy__. Практическое правило: плоская структура или элементы неизменяемы — shallow; вложенные изменяемые данные, которые надо изолировать, — deep.

Ключевые моменты

  • Три уровня. Присваивание — одна ссылка; shallow — новый контейнер, общие элементы; deep — независимая структура целиком.
  • Когда shallow опасна. Матрица как список списков: копия через [:] делит строки с оригиналом, правка ячейки видна в обоих.
  • Цена deepcopy. Рекурсивный обход всей структуры медленный; на больших графах объектов это узкое место.
  • Кастомизация. __copy__/__deepcopy__ позволяют, например, не копировать соединение с БД внутри объекта.

Практический контекст

Типичный рабочий баг: функция «скопировала» конфиг через dict.copy() и изменила вложенную секцию — изменился общий конфиг. На собеседовании это проверяют вопросом «что выведет код» с вложенным списком. Интервьюер хочет услышать модель ссылок, а не заученные названия функций; плюсом будет упоминание memo и __deepcopy__.

Пример кода

import copy

matrix = [[1, 2], [3, 4]]
shallow = matrix[:]
deep = copy.deepcopy(matrix)

shallow[0][0] = 99
print(matrix[0][0])  # 99 — строка общая с копией
print(deep[0][0])    # 1 — глубокая копия независима

Частые ошибки

  • Думают, что b = a создаёт копию списка
  • Используют [:] для вложенных структур и получают общие внутренние списки
  • Применяют deepcopy ко всему подряд, не думая о стоимости

ИП Кочкин Алексей Сергеевич · ИНН 390509026279 · ОГРНИП 325390000030973 · jiniys2005@yandex.ru