Поверхностное vs глубокое копирование в Python

Поверхностное vs глубокое копирование в Python

@python_quiz

Разберем этот квиз

Коротко: в Python функция copy.copy делает поверхностную (shallow) копию контейнера — сам контейнер новый, но вложенные объекты (например, списки внутри списка) остаются общими ссылками. copy.deepcopy клонирует структуру рекурсивно, создавая новые вложенные объекты.

Ниже — исходный код квиза и его поведение.

python

Ожидаемый вывод при запуске этого кода:

Пошаговое объяснение

  • x = [[1], [2]] — x это список из двух списков: x[0] и x[1].
  • y = copy(x) — создается новый внешний список y, но элементы (вложенные списки) копируются по ссылке. То есть y[0] и x[0] — один и тот же объект.
  • z = deepcopy(x) — создается полностью независимая копия: и внешний список, и вложенные списки — новые объекты.
  • y[0].append(3) — мы модифицируем вложенный список, который одновременно доступен через x[0] и y[0], поэтому изменение видно в x.
  • y is x — сравнивает идентичность внешних списков; это False, потому что copy создал новый объект.
  • z остается неизменным, так как deepcopy сделал независимую копию вложенных списков.

Разбор вариантов ответа (анализ предложенных строк)

  1. "[[1, 3], [2]] False [[1], [2]]"

- Совпадает с ожиданием: внешний список изменился через общую вложенную структуру, идентичность ложна, deepcopy не изменился.

  1. "[[1, 3], [2]] True [[1, 3], [2]]"

- Неверно: y is x не может быть True, т.к. copy создает новый внешний список. Кроме того, deepcopy z не должен отражать изменение, если использован deepcopy.

  1. "[[1], [2]] False [[1, 3], [2]]"

- Неверно: x должен отразить добавление 3 в первый вложенный список, а не остаться неизменным. Здесь перепутаны результаты x и z.

  1. "[[1, 3], [2]] True [[1, [2]]"

- Неверно и по форме вывода (последняя часть выглядит как синтаксическая ошибка/опечатка) и по логике: y is x не должен быть True, и z должен оставаться [[1], [2]].

Коротко: единственный вариант, который полностью соответствует поведению кода и логике shallow vs deep copy — тот, где печатается [[1, 3], [2]] False [[1], [2]].

Полезные замечания и альтернативы

  • Для плоского списка (например, список чисел) shallow copy обычно достаточно:

`python
a = [1, 2, 3]
b = a.copy() # или list(a) или copy(a)
`
b — новый список, изменения внешнего списка (добавление/удаление элементов) не затронут другой, но если элементы сами изменяемы, ссылки остаются общими.

  • Для вложенных структур используйте deepcopy:

`python
from copy import deepcopy
c = deepcopy(a_nested)
`

  • Иногда достаточно создать новые вложенные контейнеры вручную (если структура известна), это быстрее и прозрачнее, чем deepcopy:

`python
x = [[1], [2]]
y = [sublist.copy() for sublist in x] # копируем только первый уровень вложенности
`

  • Особенности производительности: deepcopy может быть дорогим для больших/сложных структур. Если вы знаете, какие уровни нужно клонировать, лучше делать это явно.

Вывод

Понимание разницы между поверхностным и глубоким копированием — ключевое при работе с вложенными изменяемыми объектами в Python. В приведённом примере поверхностная копия сохраняет ссылки на вложенные списки, поэтому изменение через копию отражается в оригинале; deepcopy создаёт полностью независимую структуру.

Report Page