Чем поверхностная копия отличается от глубокой?
- В чём разница между copy и deepcopy?
- Как правильно скопировать вложенный список?
- Почему изменение копии меняет оригинал?
Поверхностная копия создаёт новый контейнер со старыми элементами, глубокая — копирует всё рекурсивно.
- Поверхностная:
copy.copy(x),x[:],list(x),dict(x),x.copy() - Глубокая:
copy.deepcopy(x)— вложенные объекты тоже новые
А ещё Присваивание b = a не копирует вообще — это второе имя того же объекта
Подробно
Три разных действия:
- присваивание
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)копирует вложенные списки.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Поверхностная копия рекурсивно копирует вложенные списки, а deepcopy ещё и неизменяемые объекты
- ✓Поверхностная копирует только контейнер, deepcopy — всё рекурсивно
- ✗Присваивание b = a создаёт поверхностную копию списка, а copy.copy(a) — уже глубокую
- ✗list(x) и срез x[:] создают глубокую копию со всеми вложенными объектами
Что спросят дальше
Разбор темы
- Память и производительность CPython
Подсчёт ссылок и сборщик циклов, слабые ссылки, интернирование чисел и строк, копирование, сложность операций, профилирование и способы ускорения.
Связанные вопросы
- Как работают срезы в Python? Junior
- Чем отличается is от ==? Junior
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.