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

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

Пошаговое объяснение
- 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, 3], [2]] False [[1], [2]]"
- Совпадает с ожиданием: внешний список изменился через общую вложенную структуру, идентичность ложна, deepcopy не изменился.
- "[[1, 3], [2]] True [[1, 3], [2]]"
- Неверно: y is x не может быть True, т.к. copy создает новый внешний список. Кроме того, deepcopy z не должен отражать изменение, если использован deepcopy.
- "[[1], [2]] False [[1, 3], [2]]"
- Неверно: x должен отразить добавление 3 в первый вложенный список, а не остаться неизменным. Здесь перепутаны результаты x и z.
- "[[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 создаёт полностью независимую структуру.