Что делает модуль copy в Python и в чем разница между поверхностным и глубоким копированием
Что проверяют
Понимаете ли вы, что копируется в каждом случае, и знаете ли цену глубокого копирования.
Как отвечать
Модуль даёт два способа скопировать объект.
Поверхностное копирование создаёт новый объект-контейнер, но вложенные объекты остаются общими: копируются ссылки на них, а не сами объекты.
Глубокое копирование рекурсивно копирует всё дерево, поэтому новый объект полностью независим.
import copy
original = {"tags": ["a", "b"]}
shallow = copy.copy(original)
shallow["tags"].append("c")
original["tags"] # ['a', 'b', 'c'] общий список
deep = copy.deepcopy(original)
deep["tags"].append("d")
original["tags"] # не изменилсяКогда чего достаточно: если структура плоская и содержит только неизменяемые значения, поверхностного хватает, и оно заметно дешевле. Как только внутри есть изменяемые вложения, которые вы собираетесь менять, нужно глубокое.
Что стоит добавить:
- встроенные способы копирования тоже поверхностные: срез списка целиком, метод копирования словаря, конструктор из существующей коллекции. Все они дают тот же эффект, что и первый способ;
- глубокое копирование умеет обрабатывать циклические ссылки: оно ведёт таблицу уже скопированных объектов, поэтому не зацикливается и сохраняет разделяемые ссылки внутри структуры;
- стоимость: обход всего дерева. На большой вложенной структуре это заметно, и в горячем коде глубокое копирование лучше заменить на построение нужного объекта явно;
- поведение настраивается специальными методами, если объект содержит то, что нельзя копировать: открытый файл, соединение, блокировку. По умолчанию такие вещи копирование сломают;
- неизменяемые объекты не копируются вовсе, возвращается тот же объект, потому что смысла в копии нет.
Классическая ловушка той же природы: умножение списка со вложенным списком создаёт несколько ссылок на один внутренний список.
Где спотыкаются
Считают срез или копию словаря полноценной копией.
Применяют глубокое копирование по умолчанию везде и теряют производительность.
Копируют объекты с соединениями и файлами.
Попадаются на умножении списка со вложенной структурой.