Что такое поверхностная и глубокая копия (shallow copy vs deep copy)?

Краткий ответ (для собеседования): Поверхностная копия (shallow copy) создаёт новый контейнер, но кладёт в него те же самые вложенные объекты по ссылке. Если изменить вложенный объект в копии, изменения будут видны и в оригинале. Глубокая копия (deep copy) создаёт полностью независимую структуру, рекурсивно копируя все вложенные объекты; изменения в копии никак не затрагивают исходный объект.

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

Развернутое объяснение

Для изменяемых структур (списки, словари, вложенные коллекции) важно различать:

  1. простое присваивание b = a — не копия, обе переменные указывают на один и тот же объект;

  2. поверхностная копия — копируется только внешний контейнер;

  3. глубокая копия — копируется и контейнер, и все вложенные объекты.

Поверхностная копия (shallow copy)

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

Способы сделать shallow copy:

import copy
a = [[1, 2], [3, 4]]
b = a.copy()         # для списка
# или
b = list(a)
# или
b = copy.copy(a)

Поведение:

a = [[1, 2], [3, 4]]
b = a.copy()
b[0][0] = 99
print(a)  # [[99, 2], [3, 4]]
print(b)  # [[99, 2], [3, 4]]

Мы создали новый список b, но внутренние списки те же самые, поэтому изменение вложенного элемента отражается и в a.

Если же переопределить элемент верхнего уровня — поведение уже другое:

a = [[1, 2], [3, 4]]
b = a.copy()
b[0] = [99, 2]
print(a)  # [[1, 2], [3, 4]]
print(b)  # [[99, 2], [3, 4]]

Здесь мы заменили ссылку в b[0] на новый список — оригинал не изменился.

Глубокая копия (deep copy)

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

Создание:

import copy
a = [[1, 2], [3, 4]]
c = copy.deepcopy(a)
c[0][0] = 99
print(a)  # [[1, 2], [3, 4]]
print(c)  # [[99, 2], [3, 4]]

Изменения в c не затрагивают a, потому что вложенные списки тоже скопированы.

Как объяснить на собеседовании?

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

 

Читать полную статью в блоге