Получить доступ

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

JuniorПамять и копирование
Ещё спрашивают так:
  • В чём разница между copy и deepcopy?
  • Как правильно скопировать вложенный список?
  • Почему изменение копии меняет оригинал?
Коротко

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

  • Поверхностная: copy.copy(x), x[:], list(x), dict(x), x.copy()
  • Глубокая: copy.deepcopy(x) — вложенные объекты тоже новые

А ещё Присваивание b = a не копирует вообще — это второе имя того же объекта

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Три разных действия:

  • присваивание b = a — копии нет, оба имени указывают на один объект;
  • поверхностная копия — новый внешний объект, но внутри те же ссылки на вложенные объекты. Изменение самого списка копии оригинал не трогает, а изменение вложенного списка видно в обоих;
  • глубокая копия — copy.deepcopy рекурсивно копирует вложенные объекты. Она отслеживает уже скопированное (словарь memo), поэтому корректно работает с циклическими ссылками и общими подобъектами.

Неизменяемые объекты (числа, строки, кортежи из неизменяемых) не копируются даже глубоко — в этом нет смысла.

Глубокая копия медленнее и не всегда возможна: файлы, сокеты, блокировки не копируются. Свои классы могут управлять копированием через __copy__ и __deepcopy__.

Частый практический случай — матрица: [[0] * 3] * 3 создаёт три ссылки на один и тот же внутренний список. Правильно — [[0] * 3 for _ in range(3)].

Пример

import copy

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

a[0].append(99)
shallow[0]   # [1, 2, 99] — вложенный список общий
deep[0]      # [1, 2]     — независимая копия

grid = [[0] * 3] * 3
grid[0][0] = 1
grid         # [[1, 0, 0], [1, 0, 0], [1, 0, 0]] — одна строка трижды

Что хотят услышать

  • Три уровня: присваивание, поверхностная и глубокая копия.
  • Способы сделать каждую копию.
  • Пример с вложенным изменяемым объектом.
  • Ловушка с [[0] * n] * m — плюс.

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

  • Считать b = a копией.
  • Думать, что a[:] или list(a) копирует вложенные списки.

Что спросят дальше

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем